|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
namespace Microsoft.NET.Build.Tests
{
public class GivenThatWeWantToBuildADesktopExe : SdkTest
{
public GivenThatWeWantToBuildADesktopExe(ITestOutputHelper log) : base(log)
{
}
[WindowsOnlyFact]
public void It_builds_a_simple_desktop_app()
{
var targetFramework = "net45";
var testAsset = _testAssetsManager
.CopyTestAsset("HelloWorld")
.WithSource()
.WithTargetFramework(targetFramework);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory(targetFramework);
outputDirectory.Should().OnlyHaveFiles(new[] {
"HelloWorld.exe",
"HelloWorld.pdb",
"HelloWorld.exe.config"
});
}
[CoreMSBuildOnlyFact]
public void It_does_not_pass_excess_references_to_the_compiler()
{
var tfm = ToolsetInfo.CurrentTargetFramework;
var testAsset = _testAssetsManager.CopyTestAsset("AllResourcesInSatellite").WithSource().WithTargetFrameworks(tfm);
var getValues =
new GetValuesCommand(testAsset, "_SatelliteAssemblyReferences", GetValuesCommand.ValueType.Item, tfm)
{
DependsOnTargets = "CoreBuild",
WorkingDirectory = testAsset.TestRoot,
};
getValues.Execute($"-p:TargetFramework={tfm}", "-bl").Should().Pass();
var referenceAssemblies = getValues.GetValues().Select(p => Path.GetFileName(p)).Order().ToArray();
// only the 'primary' assemblies for the three potential frameworks (netcoreapp, netframework, netstandard) should be used for satellite assembly generation.
referenceAssemblies.Should().Equal(["mscorlib.dll", "netstandard.dll", "System.Runtime.dll",]);
}
[WindowsOnlyTheory]
[InlineData(true)]
[InlineData(false)]
public void RuntimeIdentifiersInferredCorrectly(bool useRidGraph)
{
Func<string, string, string> findAssembly = (a, b) => default;
findAssembly = (string path, string file) =>
{
var dir = new DirectoryInfo(path);
foreach (var folder in dir.GetDirectories())
{
var ret = findAssembly(folder.FullName, file);
if (ret is not null)
{
return ret;
}
}
foreach (var f in dir.GetFiles())
{
if (Path.GetFileName(f.FullName).Equals(file, StringComparison.OrdinalIgnoreCase))
{
return f.FullName;
}
}
return null;
};
var rootDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..");
string microsoftNetBuildTasksAssembly = findAssembly(rootDirectory, "Microsoft.NET.Build.Tasks.dll");
string ridInferenceTargets = findAssembly(rootDirectory, "Microsoft.NET.RuntimeIdentifierInference.targets");
var projectContents = @$"
<Project>
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
<UseRidGraph>{useRidGraph}</UseRidGraph>
<MicrosoftNETBuildTasksAssembly>{microsoftNetBuildTasksAssembly}</MicrosoftNETBuildTasksAssembly>
<HasRuntimeOutput>true</HasRuntimeOutput>
</PropertyGroup>
<Import Project=""{ridInferenceTargets}"" />
</Project>";
var fileLocation = Path.GetTempFileName();
try
{
File.WriteAllText(fileLocation, projectContents);
var loggers = new List<ILogger>
{
new global::Microsoft.Build.Logging.ConsoleLogger(LoggerVerbosity.Detailed)
};
var collection = new ProjectCollection(null, loggers, ToolsetDefinitionLocations.Default);
var project = collection.LoadProject(fileLocation, new Dictionary<string, string>(), null);
project.GetPropertyValue("RuntimeIdentifier").Should().Be(useRidGraph ? "win7-x86" : "win-x86");
}
finally
{
if (File.Exists(fileLocation))
{
File.Delete(fileLocation);
}
}
}
// Windows only because default RuntimeIdentifier only applies when current OS is Windows
[WindowsOnlyTheory]
[InlineData("Microsoft.DiasymReader.Native/1.7.0", false, "AnyCPU")]
[InlineData("Microsoft.DiasymReader.Native/1.7.0", true, "x86")]
[InlineData("Libuv/1.10.0", false, "x86")]
[InlineData("Libuv/1.10.0", true, "x86")]
public void PlatformTargetInferredCorrectly(string packageToReference, bool referencePlatformPackage, string expectedPlatform)
{
var testProject = new TestProject()
{
Name = "AutoRuntimeIdentifierTest",
TargetFrameworks = "net472",
IsExe = true
};
var packageElements = packageToReference.Split('/');
string packageName = packageElements[0];
string packageVersion = packageElements[1];
testProject.PackageReferences.Add(new TestPackageReference(packageName, packageVersion));
if (referencePlatformPackage)
{
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.NETCore.Platforms", "2.1.0"));
}
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: packageName + "_" + referencePlatformPackage.ToString());
var buildCommand = new BuildCommand(testAsset);
buildCommand.Execute()
.Should()
.Pass();
var getValueCommand = new GetValuesCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name), testProject.TargetFrameworks, "PlatformTarget");
getValueCommand.Execute().Should().Should();
getValueCommand.GetValues().Single().Should().Be(expectedPlatform);
}
[WindowsOnlyTheory]
// If we don't set platformTarget and don't use native dependency, we get working AnyCPU app.
[InlineData("defaults", null, false, "Native code was not used (MSIL)")]
// If we don't set platformTarget and do use native dependency, we get working x86 app.
[InlineData("defaultsNative", null, true, "Native code was used (X86)")]
// If we set x86 and don't use native dependency, we get working x86 app.
[InlineData("x86", "x86", false, "Native code was not used (X86)")]
// If we set x86 and do use native dependency, we get working x86 app.
[InlineData("x86Native", "x86", true, "Native code was used (X86)")]
// If we set x64 and don't use native dependency, we get working x64 app.
[InlineData("x64", "x64", false, "Native code was not used (Amd64)")]
// If we set x64 and do use native dependency, we get working x64 app.
[InlineData("x64Native", "x64", true, "Native code was used (Amd64)")]
// If we set AnyCPU and don't use native dependency, we get working AnyCPU app.
[InlineData("AnyCPU", "AnyCPU", false, "Native code was not used (MSIL)")]
// If we set AnyCPU and do use native dependency, we get any CPU app that can't find its native dependency.
// Tests current behavior, but ideally we'd also raise a build diagnostic in this case: https://github.com/dotnet/sdk/issues/843
[InlineData("AnyCPUNative", "AnyCPU", true, "Native code failed (MSIL)")]
public void It_handles_native_dependencies_and_platform_target(
string identifier,
string platformTarget,
bool useNativeCode,
string expectedProgramOutput)
{
foreach (bool multiTarget in new[] { false, true })
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopMinusRid", identifier: Path.DirectorySeparatorChar + identifier + (multiTarget ? "Multi" : ""))
.WithSource()
.WithProjectChanges(project =>
{
var ns = project.Root.Name.Namespace;
var propertyGroup = project.Root.Elements(ns + "PropertyGroup").First();
propertyGroup.Add(new XElement(ns + "UseNativeCode", useNativeCode));
if (platformTarget != null)
{
propertyGroup.Add(new XElement(ns + "PlatformTarget", platformTarget));
}
if (multiTarget)
{
propertyGroup.Element(ns + "TargetFramework").Remove();
propertyGroup.Add(new XElement(ns + "TargetFrameworks", "net46;netcoreapp1.1"));
}
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var exe = Path.Combine(buildCommand.GetOutputDirectory("net46").FullName, "DesktopMinusRid.exe");
var runCommand = new RunExeCommand(Log, exe);
runCommand
.Execute()
.Should()
.Pass()
.And
.HaveStdOutContaining(expectedProgramOutput);
}
}
[Theory]
[InlineData("false", false)]
[InlineData("true", true)]
[InlineData("", false)]
public void It_includes_platform_in_output_path_if_requested(string appendPlatformValue, bool shouldIncludePlatform)
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopMinusRid")
.WithSource()
.WithProjectChanges(project =>
{
var ns = project.Root.Name.Namespace;
var propertyGroup = project.Root.Elements(ns + "PropertyGroup").First();
propertyGroup.Add(new XElement(ns + "AppendPlatformToOutputPath", appendPlatformValue));
});
var buildCommand = new BuildCommand(testAsset);
buildCommand.Execute().Should().Pass();
var outputDirectory = buildCommand.GetOutputDirectory("net46", platform: shouldIncludePlatform ? "AnyCPU" : "");
outputDirectory.GetFiles("DesktopMinusRid.exe").Length.Should().Be(1);
}
[WindowsOnlyTheory]
// implicit rid with option to append rid to output path off -> do not append
[InlineData("implicitOff", "", false, false)]
// implicit rid with option to append rid to output path on -> do not append (never append implicit rid irrespective of option)
[InlineData("implicitOn", "", true, false)]
// explicit rid with option to append rid to output path off -> do not append
[InlineData("explicitOff", $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x86", false, false)]
// explicit rid with option to append rid to output path on -> append
[InlineData("explicitOn", $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x64", true, true)]
public void It_appends_rid_to_outdir_correctly(string identifier, string rid, bool useAppendOption, bool shouldAppend)
{
foreach (bool multiTarget in new[] { false, true })
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopMinusRid", identifier: Path.DirectorySeparatorChar + identifier + (multiTarget ? "Multi" : ""))
.WithSource()
.WithProjectChanges(project =>
{
var ns = project.Root.Name.Namespace;
var propertyGroup = project.Root.Elements(ns + "PropertyGroup").First();
propertyGroup.Add(new XElement(ns + "RuntimeIdentifier", rid));
propertyGroup.Add(new XElement(ns + "AppendRuntimeIdentifierToOutputPath", useAppendOption.ToString()));
if (multiTarget)
{
propertyGroup.Element(ns + "RuntimeIdentifier").Add(new XAttribute("Condition", "'$(TargetFramework)' == 'net46'"));
propertyGroup.Element(ns + "TargetFramework").Remove();
propertyGroup.Add(new XElement(ns + "TargetFrameworks", "net46;netcoreapp1.1"));
}
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var publishCommand = new PublishCommand(testAsset);
publishCommand
.Execute(multiTarget ? new[] { "/p:TargetFramework=net46" } : Array.Empty<string>())
.Should()
.Pass();
string expectedOutput;
switch (rid)
{
case "":
expectedOutput = "Native code was not used (MSIL)";
break;
case $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x86":
expectedOutput = "Native code was not used (X86)";
break;
case $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x64":
expectedOutput = "Native code was not used (Amd64)";
break;
default:
throw new ArgumentOutOfRangeException(nameof(rid));
}
var outputDirectory = buildCommand.GetOutputDirectory("net46", runtimeIdentifier: shouldAppend ? rid : "");
var publishDirectory = publishCommand.GetOutputDirectory("net46", runtimeIdentifier: rid);
foreach (var directory in new[] { outputDirectory, publishDirectory })
{
var exe = Path.Combine(directory.FullName, "DesktopMinusRid.exe");
var runCommand = new RunExeCommand(Log, exe);
runCommand
.Execute()
.Should()
.Pass()
.And
.HaveStdOutContaining(expectedOutput);
}
}
}
[WindowsOnlyTheory]
[InlineData("win7-x86", "x86")]
[InlineData("win8-x86-aot", "x86")]
[InlineData("win7-x64", "x64")]
[InlineData("win8-x64-aot", "x64")]
[InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm", "arm")]
[InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm-aot", "arm")]
[InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm64", "arm64")]
[InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm64-aot", "arm64")]
// cpu architecture is never expected at the front
[InlineData("x86-something", "AnyCPU")]
[InlineData("x64-something", "AnyCPU")]
[InlineData("arm-something", "AnyCPU")]
public void It_builds_with_inferred_platform_target(string runtimeIdentifier, string expectedPlatformTarget)
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopMinusRid", identifier: Path.DirectorySeparatorChar + runtimeIdentifier)
.WithSource();
var getValuesCommand = new GetValuesCommand(Log, testAsset.TestRoot,
"net46", "PlatformTarget", GetValuesCommand.ValueType.Property);
getValuesCommand
.Execute($"/p:RuntimeIdentifier={runtimeIdentifier}")
.Should()
.Pass();
getValuesCommand
.GetValues()
.Should()
.BeEquivalentTo(expectedPlatformTarget);
}
[WindowsOnlyFact]
public void It_respects_explicit_platform_target()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopMinusRid")
.WithSource();
var getValuesCommand = new GetValuesCommand(Log, testAsset.TestRoot,
"net46", "PlatformTarget", GetValuesCommand.ValueType.Property);
getValuesCommand
.Execute($"/p:RuntimeIdentifier={ToolsetInfo.LatestWinRuntimeIdentifier}-x86", "/p:PlatformTarget=x64")
.Should()
.Pass();
getValuesCommand
.GetValues()
.Should()
.BeEquivalentTo("x64");
}
[WindowsOnlyFact]
public void It_includes_default_framework_references()
{
var testProject = new TestProject()
{
Name = "DefaultReferences",
// TODO: Add net35 to the TargetFrameworks list once https://github.com/Microsoft/msbuild/issues/1333 is fixed
TargetFrameworks = "net40;net45;net462",
IsExe = true
};
string sourceFile =
@"using System;
namespace DefaultReferences
{
public class TestClass
{
public static void Main(string [] args)
{
var uri = new System.Uri(""http://github.com/dotnet/corefx"");
var currentProcess = System.Diagnostics.Process.GetCurrentProcess();
}
}
}";
testProject.SourceFiles.Add("TestClass.cs", sourceFile);
var testAsset = _testAssetsManager.CreateTestProject(testProject);
var buildCommand = new BuildCommand(testAsset, "DefaultReferences");
buildCommand
.Execute()
.Should()
.Pass()
.And
.NotHaveStdOutMatching("Could not resolve this reference", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
[WindowsOnlyFact]
public void It_reports_a_single_failure_if_reference_assemblies_are_not_found()
{
var testProject = new TestProject()
{
Name = "MissingReferenceAssemblies",
// A version of .NET we don't expect to exist
TargetFrameworks = "net469",
IsExe = true
};
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name);
var buildCommand = new BuildCommand(testAsset);
// Pass "/clp:summary" so that we can check output for string "1 Error(s)"
var result = buildCommand.Execute("/clp:summary");
result.Should().Fail();
// Error code for reference assemblies not found
result.StdOut.Should().Contain("MSB3644");
// Error code for exception generated from task
result.StdOut.Should().NotContain("MSB4018");
// Ensure no other errors are generated
result.StdOut.Should().Contain("1 Error(s)");
}
[WindowsOnlyFact]
public void It_does_not_report_conflicts_if_the_same_framework_assembly_is_referenced_multiple_times()
{
var testProject = new TestProject()
{
Name = "DuplicateFrameworkReferences",
TargetFrameworks = "net462",
IsExe = true
};
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
var itemGroup = new XElement(ns + "ItemGroup");
p.Root.Add(itemGroup);
itemGroup.Add(new XElement(ns + "Reference", new XAttribute("Include", "System")));
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute("/v:normal")
.Should()
.Pass()
.And
.NotHaveStdOutMatching("Encountered conflict", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
[WindowsOnlyFact]
public void It_does_not_report_conflicts_when_referencing_a_nuget_package()
{
var testProject = new TestProject()
{
Name = "DesktopConflictsNuGet",
TargetFrameworks = "net462",
IsExe = true
};
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
var itemGroup = new XElement(ns + "ItemGroup");
p.Root.Add(itemGroup);
itemGroup.Add(new XElement(ns + "PackageReference",
new XAttribute("Include", "NewtonSoft.Json"),
new XAttribute("Version", ToolsetInfo.GetNewtonsoftJsonPackageVersion())));
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute("/v:normal")
.Should()
.Pass()
.And
.NotHaveStdOutMatching("Encountered conflict", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
[Fact]
public void It_does_not_report_conflicts_when_with_http_4_1_package()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
var testProject = new TestProject()
{
Name = "DesktopConflictsHttp4_1",
TargetFrameworks = "net462",
IsExe = true
};
testProject.PackageReferences.Add(new TestPackageReference("System.Net.Http", "4.1.0"));
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name);
var buildCommand = new BuildCommand(testAsset);
// Verify that ResolveAssemblyReference doesn't generate any conflicts
buildCommand
.Execute("/v:normal")
.Should()
.Pass()
.And
.NotHaveStdOutMatching("MSB3243", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
[WindowsOnlyFact]
public void It_does_not_report_conflicts_with_runtime_specific_items()
{
var testProject = new TestProject()
{
Name = "DesktopConflictsRuntimeTargets",
TargetFrameworks = "net462",
IsExe = true
};
testProject.AdditionalProperties["PlatformTarget"] = "AnyCPU";
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
var itemGroup = new XElement(ns + "ItemGroup");
p.Root.Add(itemGroup);
itemGroup.Add(new XElement(ns + "PackageReference",
new XAttribute("Include", "System.Security.Cryptography.Algorithms"),
new XAttribute("Version", "4.3.0")));
});
var buildCommand = new BuildCommand(testAsset);
var buildResult = buildCommand
.Execute("/v:normal");
buildResult.Should().Pass();
// Correct asset should be copied to output folder. Before fixing https://github.com/dotnet/sdk/issues/1510,
// the runtimeTargets items would win conflict resolution, and then would not be copied to the output folder,
// so there'd be no copy of the DLL in the output folder.
var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks);
outputDirectory.Should().HaveFile("System.Security.Cryptography.Algorithms.dll");
// There should be no conflicts
buildResult.Should().NotHaveStdOutMatching("Encountered conflict", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
[FullMSBuildOnlyTheory]
[InlineData("4.3.3")]
[InlineData("4.1.0")]
public void It_builds_successfully_if_inbox_assembly_wins_conflict_resolution(string httpPackageVersion)
{
Test_inbox_assembly_wins_conflict_resolution(false, httpPackageVersion);
}
[WindowsOnlyTheory]
[InlineData("4.3.3")]
[InlineData("4.1.0")]
public void It_builds_successfully_if_inbox_assembly_wins_conflict_resolution_sdk(string httpPackageVersion)
{
Test_inbox_assembly_wins_conflict_resolution(true, httpPackageVersion);
}
void Test_inbox_assembly_wins_conflict_resolution(bool useSdkProject, string httpPackageVersion, bool useAlias = false)
{
var testProject = new TestProject()
{
Name = "DesktopInBoxConflictResolution",
IsExe = true
};
if (useSdkProject)
{
testProject.TargetFrameworks = "net472";
}
else
{
testProject.IsSdkProject = false;
testProject.TargetFrameworkVersion = "v4.7.2";
}
testProject.PackageReferences.Add(new TestPackageReference("System.Net.Http", httpPackageVersion));
testProject.SourceFiles["Program.cs"] =
(useAlias ? "extern alias snh;" + Environment.NewLine : "") +
@"using System;
class Program
{
static void Main(string[] args)
{
" +
(useAlias ? "var client = new snh::System.Net.Http.HttpClient();" :
"var client = new System.Net.Http.HttpClient();") +
@"
}
}";
string identifier = (useSdkProject ? "_SDK_" : "_") +
(useAlias ? "alias" : "") +
httpPackageVersion;
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name, identifier)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
var itemGroup = new XElement(ns + "ItemGroup");
p.Root.Add(itemGroup);
var httpReference = new XElement(ns + "Reference",
new XAttribute("Include", "System.Net.Http"));
if (useAlias)
{
httpReference.SetAttributeValue("Aliases", "snh");
}
itemGroup.Add(httpReference);
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute("/v:normal")
.Should()
.Pass()
.And.NotHaveStdOutContaining("MSB3277") // MSB3277: Found conflicts between different versions of the same dependent assembly that could not be resolved.
.And.NotHaveStdOutContaining("MSB3243") // MSB3243: No way to resolve conflict between...
.And.NotHaveStdOutContaining("Could not determine");
}
[FullMSBuildOnlyTheory(Skip = "https://github.com/dotnet/NuGet.BuildTasks/issues/75")]
[InlineData("4.3.3")]
[InlineData("4.1.0")]
public void Aliases_are_preserved_if_inbox_assembly_wins_conflict_resolution(string httpPackageVersion)
{
Test_inbox_assembly_wins_conflict_resolution(false, httpPackageVersion, useAlias: true);
}
[WindowsOnlyTheory]
[InlineData("4.3.3")]
[InlineData("4.1.0")]
public void Aliases_are_preserved_if_inbox_assembly_wins_conflict_resolution_sdk(string httpPackageVersion)
{
Test_inbox_assembly_wins_conflict_resolution(true, httpPackageVersion, useAlias: true);
}
[WindowsOnlyFact]
public void Aliases_are_preserved_if_framework_reference_is_overridden_by_package()
{
var testProject = new TestProject()
{
Name = "OverriddenAlias",
IsExe = true,
TargetFrameworks = "net462"
};
testProject.PackageReferences.Add(new TestPackageReference("System.Net.Http", "4.3.3"));
testProject.SourceFiles["Program.cs"] = @"
extern alias snh;
using System;
class Program
{
static void Main(string[] args)
{
var client = new snh::System.Net.Http.HttpClient();
}
}";
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
var itemGroup = new XElement(ns + "ItemGroup");
p.Root.Add(itemGroup);
var httpReference = new XElement(ns + "Reference",
new XAttribute("Include", "System.Net.Http"));
httpReference.SetAttributeValue("Aliases", "snh");
itemGroup.Add(httpReference);
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
}
[WindowsOnlyFact]
public void It_generates_binding_redirects_if_needed()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource();
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory("net452", runtimeIdentifier: $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x86");
outputDirectory.Should().HaveFiles(new[] {
"DesktopNeedsBindingRedirects.exe",
"DesktopNeedsBindingRedirects.exe.config"
});
XElement root = XElement.Load(outputDirectory.GetFiles("DesktopNeedsBindingRedirects.exe.config").Single().FullName);
root.Elements("runtime").Single().Elements().Should().Contain(e => e.Name.LocalName == "assemblyBinding");
}
[WindowsOnlyFact]
public void It_generates_supportedRuntime_when_no_appconfig_in_source_require_binding_redirect()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource();
XElement root = BuildTestAssetGetAppConfig(testAsset);
root.Elements("startup").Single().Elements().Should().Contain(e => e.Name.LocalName == "supportedRuntime");
}
[WindowsOnlyFact]
public void It_generates_appconfig_incrementally()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource();
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
FileInfo outputfile = buildCommand
.GetIntermediateDirectory("net452", runtimeIdentifier: $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x86")
.GetFiles("DesktopNeedsBindingRedirects.exe.withSupportedRuntime.config").Single();
DateTime firstBuildWriteTime = File.GetLastWriteTimeUtc(outputfile.FullName);
buildCommand
.Execute()
.Should()
.Pass();
DateTime secondBuildBuildWriteTime = File.GetLastWriteTimeUtc(outputfile.FullName);
secondBuildBuildWriteTime.Should().Be(firstBuildWriteTime);
}
[WindowsOnlyFact]
public void It_generates_supportedRuntime_when_no_appconfig_in_source_does_not_require_binding_redirect()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource()
.WithProjectChanges(project =>
{
var ns = project.Root.Name.Namespace;
var propertyGroup = project.Root.Elements(ns + "ItemGroup").First();
propertyGroup.Elements(ns + "PackageReference").Remove();
});
XElement root = BuildTestAssetGetAppConfig(testAsset);
root.Elements("startup").Single()
.Elements().Should()
.Contain(e => e.Name.LocalName == "supportedRuntime");
}
[WindowsOnlyFact]
public void It_generates_supportedRuntime_when_there_is_appconfig_with_supportedRuntime_in_source_require_binding_redirect()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource();
var appconfigWithoutSupportedRuntime = new XDocument(
new XDeclaration("1.0", "utf-8", "true"),
new XElement("configuration",
new XElement("startup",
new XElement("supportedRuntime",
new XAttribute("version", "v999")))));
appconfigWithoutSupportedRuntime.Save(
Path.Combine(testAsset.TestRoot, "App.Config"));
XElement root = BuildTestAssetGetAppConfig(testAsset);
root.Elements("startup").Single()
.Elements("supportedRuntime").Single()
.Should().HaveAttributeWithValue("version", "v999", "It should keep existing supportedRuntime");
}
[WindowsOnlyFact]
public void It_generates_supportedRuntime_when_there_is_appconfig_without_supportedRuntime_in_source_require_binding_redirect()
{
var testAsset = _testAssetsManager
.CopyTestAsset("DesktopNeedsBindingRedirects")
.WithSource();
var appconfigWithoutSupportedRuntime = new XDocument(
new XDeclaration("1.0", "utf-8", "true"),
new XElement("configuration",
new XElement("appSettings")));
appconfigWithoutSupportedRuntime.Save(
Path.Combine(testAsset.TestRoot, "App.Config"));
XElement root = BuildTestAssetGetAppConfig(testAsset);
root.Elements("startup").Single().Elements().Should().Contain(e => e.Name.LocalName == "supportedRuntime");
root.Should().HaveElement("appSettings",
"It should keep existing appconfig's setting");
}
private XElement BuildTestAssetGetAppConfig(TestAsset testAsset)
{
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
DirectoryInfo outputDirectory = buildCommand.GetOutputDirectory("net452", runtimeIdentifier: $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x86");
return XElement.Load(outputDirectory.GetFiles("DesktopNeedsBindingRedirects.exe.config").Single().FullName);
}
[WindowsOnlyTheory]
[InlineData(true)]
[InlineData(false)]
public void It_places_package_satellites_correctly(bool crossTarget)
{
var testProject = new TestProject()
{
Name = "DesktopUsingPackageWithSatellites",
TargetFrameworks = "net46",
IsExe = true
};
if (crossTarget)
{
testProject.Name += "_cross";
}
testProject.PackageReferences.Add(new TestPackageReference("FluentValidation", "5.5.0"));
var testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name)
.WithProjectChanges(project =>
{
if (crossTarget)
{
var ns = project.Root.Name.Namespace;
var propertyGroup = project.Root.Elements(ns + "PropertyGroup").First();
propertyGroup.Element(ns + "TargetFramework").Name += "s";
}
});
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute("/v:normal")
.Should()
.Pass()
.And
.NotHaveStdOutMatching("Encountered conflict", System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks);
outputDirectory.Should().NotHaveFile("FluentValidation.resources.dll");
outputDirectory.Should().HaveFile(@"fr\FluentValidation.resources.dll");
}
[WindowsOnlyFact(Skip = "https://github.com/NuGet/Home/issues/6823")]
public void It_allows_TargetFrameworkVersion_to_be_capitalized()
{
var testProject = new TestProject()
{
Name = "UppercaseTargetFrameworkVersion",
IsSdkProject = false,
IsExe = true,
TargetFrameworkVersion = "V4.6.2"
};
var testAsset = _testAssetsManager.CreateTestProject(testProject);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
}
[Fact]
public void It_places_package_xml_in_ref_folder_in_output_directory()
{
var testProject = new TestProject()
{
Name = "DesktopUsingPackageWithdXmlInRefFolder",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};
// This package contains an xml in ref, but not in lib.
testProject.PackageReferences.Add(new TestPackageReference("system.diagnostics.debug", "4.3.0"));
testProject.AdditionalProperties.Add("CopyDebugSymbolFilesFromPackages", "true");
testProject.AdditionalProperties.Add("CopyDocumentationFilesFromPackages", "true");
// we need to disable package pruning to ensure that the xml file is copied
// from the packagereference - otherwise this dependency will be satisfied
// by the framework reference and the xml file will not be copied.
testProject.AdditionalProperties.Add("RestoreEnablePackagePruning", "false");
TestAsset testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.WithWorkingDirectory(testAsset.TestRoot)
.Execute("/bl:{}.binlog")
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks);
// this xml is coming from ref folder
outputDirectory.Should().HaveFile("System.Diagnostics.Debug.xml");
}
[WindowsOnlyTheory]
[InlineData("true", "true")]
[InlineData("true", "false")]
[InlineData("false", "true")]
[InlineData("false", "false")]
public void It_places_package_pdb_and_xml_files_in_output_directory(string enableCopyDebugSymbolFilesFromPackages, string enableDocumentationFilesFromPackages)
{
var testProject = new TestProject()
{
Name = "DesktopUsingPackageWithPdbAndXml",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.Build", "17.3.1"));
testProject.AdditionalProperties.Add("CopyDebugSymbolFilesFromPackages", enableCopyDebugSymbolFilesFromPackages);
testProject.AdditionalProperties.Add("CopyDocumentationFilesFromPackages", enableDocumentationFilesFromPackages);
string testPath = enableCopyDebugSymbolFilesFromPackages + enableDocumentationFilesFromPackages;
TestAsset testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name, identifier: testPath);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks);
HelperCheckPdbAndDocumentation(outputDirectory, "Microsoft.Build", enableCopyDebugSymbolFilesFromPackages, enableDocumentationFilesFromPackages);
}
[WindowsOnlyTheory]
[InlineData("true", "true")]
[InlineData("true", "false")]
[InlineData("false", "true")]
[InlineData("false", "false")]
public void It_places_package_pdb_and_xml_files_from_project_references_in_output_directory(string enableCopyDebugSymbolFilesFromPackages, string enableDocumentationFilesFromPackages)
{
var libraryProject = new TestProject()
{
Name = "ProjectWithPackage",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = false,
};
libraryProject.PackageReferences.Add(new TestPackageReference("Microsoft.Build", "17.3.1"));
var consumerProject = new TestProject()
{
Name = "ConsumerProject",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};
consumerProject.AdditionalProperties.Add("CopyDebugSymbolFilesFromPackages", enableCopyDebugSymbolFilesFromPackages);
consumerProject.AdditionalProperties.Add("CopyDocumentationFilesFromPackages", enableDocumentationFilesFromPackages);
consumerProject.ReferencedProjects.Add(libraryProject);
string testPath = enableCopyDebugSymbolFilesFromPackages + enableDocumentationFilesFromPackages;
TestAsset testAsset = _testAssetsManager.CreateTestProject(consumerProject, consumerProject.Name, identifier: testPath);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory(libraryProject.TargetFrameworks);
HelperCheckPdbAndDocumentation(outputDirectory, "Microsoft.Build", enableCopyDebugSymbolFilesFromPackages, enableDocumentationFilesFromPackages);
}
[WindowsOnlyTheory]
[InlineData("true", "true")]
[InlineData("true", "false")]
[InlineData("false", "true")]
[InlineData("false", "false")]
public void It_places_package_pdb_and_xml_files_in_publish_directory(string enableCopyDebugSymbolFilesFromPackages, string enableDocumentationFilesFromPackages)
{
var testProject = new TestProject()
{
Name = "DesktopPublishPackageWithPdbAndXml",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.Build", "17.3.1"));
testProject.AdditionalProperties.Add("CopyDebugSymbolFilesFromPackages", enableCopyDebugSymbolFilesFromPackages);
testProject.AdditionalProperties.Add("CopyDocumentationFilesFromPackages", enableDocumentationFilesFromPackages);
string testPath = enableCopyDebugSymbolFilesFromPackages + enableDocumentationFilesFromPackages;
TestAsset testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name, identifier: testPath);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var publishCommand = new PublishCommand(testAsset);
publishCommand
.Execute()
.Should()
.Pass();
var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
HelperCheckPdbAndDocumentation(publishDirectory, "Microsoft.Build", enableCopyDebugSymbolFilesFromPackages, enableDocumentationFilesFromPackages);
}
[WindowsOnlyFact]
public void It_places_package_xml_files_in_output_directory_but_not_in_publish()
{
var testProject = new TestProject()
{
Name = "DesktopPackageWithXmlNotPublished",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.Build", "17.3.1"));
testProject.AdditionalProperties.Add("PublishReferencesDocumentationFiles", "false");
testProject.AdditionalProperties.Add("CopyDocumentationFilesFromPackages", "true");
TestAsset testAsset = _testAssetsManager.CreateTestProject(testProject, testProject.Name);
var buildCommand = new BuildCommand(testAsset);
buildCommand
.Execute()
.Should()
.Pass();
var publishCommand = new PublishCommand(testAsset);
publishCommand
.Execute()
.Should()
.Pass();
var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks);
var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
outputDirectory.Should().HaveFile("Microsoft.Build.xml");
publishDirectory.Should().NotHaveFile("Microsoft.Build.xml");
}
void HelperCheckPdbAndDocumentation(
DirectoryInfo directoryInfo,
string packageName,
string enableCopyDebugSymbolFilesFromPackages,
string enableDocumentationFilesFromPackages)
{
string assemblyFile = packageName + ".dll";
string pdbFile = packageName + ".pdb";
string docFile = packageName + ".xml";
ShouldHave(assemblyFile);
if (enableCopyDebugSymbolFilesFromPackages == "true")
{
ShouldHave(pdbFile);
}
else
{
ShouldNotHave(pdbFile);
}
if (enableDocumentationFilesFromPackages == "true")
{
ShouldHave(docFile);
}
else
{
ShouldNotHave(docFile);
}
void ShouldHave(string file) => directoryInfo.Should().HaveFile(file);
void ShouldNotHave(string file) => directoryInfo.Should().NotHaveFile(file);
}
}
}
|