|
// 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 System.Runtime.CompilerServices;
namespace Microsoft.NET.Build.Tests
{
public class DesignTimeBuildTests : SdkTest
{
public DesignTimeBuildTests(ITestOutputHelper log) : base(log)
{
}
[Theory]
[InlineData("TestLibrary", null)]
[InlineData("TestApp", null)]
[InlineData("TestApp", "netcoreapp2.1")]
[InlineData("TestApp", ToolsetInfo.CurrentTargetFramework)]
public void The_design_time_build_succeeds_before_nuget_restore(string relativeProjectPath, string targetFramework)
{
var args = GetDesignTimeMSBuildArgs();
if (args == null)
{
// Design-time targets couldn't be found
return;
}
var testAsset = _testAssetsManager
.CopyTestAsset("AppWithLibrary", identifier: relativeProjectPath + "_" + targetFramework ?? string.Empty)
.WithSource()
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
// Add dummy target called by design-time build which may not yet be defined in the version
// of Visual Studio we are testing with.
p.Root.Add(new XElement(ns + "Target",
new XAttribute("Name", "CollectFrameworkReferences")));
})
.WithTargetFramework(targetFramework, relativeProjectPath);
var projectDirectory = Path.Combine(testAsset.TestRoot, relativeProjectPath);
var command = new MSBuildCommand(Log, "ResolveAssemblyReferencesDesignTime", projectDirectory)
{
WorkingDirectory = projectDirectory
};
var result = command.Execute(args);
result.Should().Pass();
}
[Fact]
public void DesignTimeBuildSucceedsAfterTargetFrameworkIsChanged()
{
TestDesignTimeBuildAfterChange(project =>
{
var ns = project.Root.Name.Namespace;
project.Root.Element(ns + "PropertyGroup")
.Element(ns + "TargetFramework")
.SetValue(ToolsetInfo.CurrentTargetFramework);
});
}
[Fact]
public void DesignTimeBuildSucceedsAfterRuntimeIdentifierIsChanged()
{
TestDesignTimeBuildAfterChange(project =>
{
var ns = project.Root.Name.Namespace;
project.Root.Element(ns + "PropertyGroup")
.Add(new XElement(ns + "RuntimeIdentifier", $"{ToolsetInfo.LatestWinRuntimeIdentifier}-x64"));
});
}
// Regression test for https://github.com/dotnet/sdk/issues/13513
// https://github.com/dotnet/sdk/issues/49665
// error : NETSDK1056: Project is targeting runtime 'osx-arm64' but did not resolve any runtime-specific packages. This runtime may not be supported by the target framework.
[PlatformSpecificFact(TestPlatforms.Any & ~TestPlatforms.OSX)]
public void DesignTimeBuildSucceedsWhenTargetingNetCore21WithRuntimeIdentifier()
{
var testProject = new TestProject()
{
Name = "DesignTimePackageDependencies",
TargetFrameworks = "netcoreapp2.1",
IsSdkProject = true,
RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid()
};
var testAsset = _testAssetsManager.CreateTestProject(testProject);
new MSBuildCommand(testAsset, "ResolvePackageDependenciesDesignTime")
.Execute()
.Should()
.Pass();
}
[Theory]
[InlineData("netcoreapp3.0")]
[InlineData(ToolsetInfo.CurrentTargetFramework)]
[InlineData($"{ToolsetInfo.CurrentTargetFramework}-windows")]
[InlineData($"{ToolsetInfo.CurrentTargetFramework}-windows7.0")]
public void DesignTimePackageDependenciesAreResolved(string targetFramework)
{
var testProject = new TestProject()
{
Name = "DesignTimePackageDependencies",
TargetFrameworks = targetFramework,
};
testProject.PackageReferences.Add(new TestPackageReference("Newtonsoft.Json", ToolsetInfo.GetNewtonsoftJsonPackageVersion(), privateAssets: "All"));
testProject.PackageReferences.Add(new TestPackageReference("Humanizer", "2.8.26"));
// disable implicit use of the Roslyn Toolset compiler package
testProject.AdditionalProperties["BuildWithNetFrameworkHostedCompiler"] = false.ToString();
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
var getValuesCommand = new GetValuesCommand(testAsset, "_PackageDependenciesDesignTime", GetValuesCommand.ValueType.Item)
{
DependsOnTargets = "ResolvePackageDependenciesDesignTime"
};
getValuesCommand.Execute()
.Should()
.Pass();
getValuesCommand.GetValues()
.Should()
.BeEquivalentTo($"Newtonsoft.Json/{ToolsetInfo.GetNewtonsoftJsonPackageVersion()}", "Humanizer/2.8.26");
}
[Theory]
[InlineData("netcoreapp3.0")]
[InlineData(ToolsetInfo.CurrentTargetFramework)]
[InlineData($"{ToolsetInfo.CurrentTargetFramework}-windows")]
[InlineData($"{ToolsetInfo.CurrentTargetFramework}-windows7.0")]
public void PackageErrorsAreSet(string targetFramework)
{
var designTimeArgs = GetDesignTimeMSBuildArgs();
if (designTimeArgs == null)
{
// Design-time targets couldn't be found
return;
}
var testProject = new TestProject()
{
Name = "DesignTimePackageDependencies",
TargetFrameworks = targetFramework,
};
// Downgrade will cause an error
testProject.AdditionalProperties["ContinueOnError"] = "ErrorAndContinue";
testProject.PackageReferences.Add(new TestPackageReference("NuGet.Commands", "4.0.0"));
testProject.PackageReferences.Add(new TestPackageReference("NuGet.Packaging", "3.5.0"));
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
new RestoreCommand(testAsset)
.Execute()
.Should()
.Fail();
var getValuesCommand = new GetValuesCommand(testAsset, "_PackageDependenciesDesignTime", GetValuesCommand.ValueType.Item)
{
ShouldRestore = false,
DependsOnTargets = "ResolvePackageDependenciesDesignTime",
MetadataNames = new List<string>() { "DiagnosticLevel" }
};
getValuesCommand
.WithWorkingDirectory(testAsset.TestRoot)
.Execute(designTimeArgs)
.Should()
.Fail();
var valuesWithMetadata = getValuesCommand.GetValuesWithMetadata();
var nugetPackagingMetadata = valuesWithMetadata.Single(kvp => kvp.value.Equals("NuGet.Packaging/3.5.0")).metadata;
nugetPackagingMetadata["DiagnosticLevel"].Should().Be("Error");
}
private void TestDesignTimeBuildAfterChange(Action<XDocument> projectChange, [CallerMemberName] string callingMethod = "")
{
var designTimeArgs = GetDesignTimeMSBuildArgs();
if (designTimeArgs == null)
{
// Design-time targets couldn't be found
return;
}
var testProject = new TestProject()
{
Name = "App",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true
};
// Add some package references to test more code paths (such as in ResolvePackageAssets)
testProject.PackageReferences.Add(new TestPackageReference("Newtonsoft.Json", ToolsetInfo.GetNewtonsoftJsonPackageVersion(), privateAssets: "All"));
testProject.PackageReferences.Add(new TestPackageReference("Humanizer", "2.8.26"));
// Use a test-specific packages folder
testProject.AdditionalProperties["RestorePackagesPath"] = @"$(MSBuildProjectDirectory)\packages";
var testAsset = _testAssetsManager.CreateTestProject(testProject, callingMethod: callingMethod)
.WithProjectChanges(p =>
{
var ns = p.Root.Name.Namespace;
// Add dummy target called by design-time build which may not yet be defined in the version
// of Visual Studio we are testing with.
p.Root.Add(new XElement(ns + "Target",
new XAttribute("Name", "CollectFrameworkReferences")));
});
string projectFolder = Path.Combine(testAsset.TestRoot, testProject.Name);
var buildCommand = new MSBuildCommand(Log, null, projectFolder)
{
WorkingDirectory = projectFolder
};
buildCommand
.Execute()
.Should()
.Pass();
string projectFilePath = Path.Combine(projectFolder, testProject.Name + ".csproj");
var project = XDocument.Load(projectFilePath);
projectChange(project);
project.Save(projectFilePath);
buildCommand
.ExecuteWithoutRestore(designTimeArgs)
.Should()
.Pass();
buildCommand
.Execute()
.Should()
.Pass();
buildCommand
.ExecuteWithoutRestore(designTimeArgs)
.Should()
.Pass();
}
private static string[] GetDesignTimeMSBuildArgs()
{
// This test needs the design-time targets, which come with Visual Studio. So we will use the VSINSTALLDIR
// environment variable to find the install path to Visual Studio and the design-time targets under it.
// This will be set when running from a developer command prompt. Unfortunately, unless VS is launched
// from a developer command prompt, it won't be set when running tests from VS. So in that case the
// test will simply be skipped.
string vsInstallDir = Environment.GetEnvironmentVariable("VSINSTALLDIR");
if (vsInstallDir == null)
{
return null;
}
string csharpDesignTimeTargets = Path.Combine(vsInstallDir, @"MSBuild\Microsoft\VisualStudio\Managed\Microsoft.CSharp.DesignTime.targets");
var args = new[]
{
"/p:DesignTimeBuild=true",
"/p:SkipCompilerExecution=true",
"/p:ProvideCommandLineArgs=true",
$"/p:CSharpDesignTimeTargetsPath={csharpDesignTimeTargets}",
"/t:CollectResolvedSDKReferencesDesignTime;CollectPackageReferences;ResolveComReferencesDesignTime",
"/t:ResolveProjectReferencesDesignTime;BuiltProjectOutputGroup;CollectFrameworkReferences",
"/t:CollectUpToDateCheckBuiltDesignTime;CollectPackageDownloads;ResolveAssemblyReferencesDesignTime",
"/t:CollectAnalyzersDesignTime;CollectSDKReferencesDesignTime;CollectUpToDateCheckInputDesignTime",
"/t:CollectUpToDateCheckOutputDesignTime;ResolvePackageDependenciesDesignTime;CompileDesignTime",
"/t:CollectResolvedCompilationReferencesDesignTime;ResolveFrameworkReferences",
// Set targeting pack folder to nonexistant folder so the project won't use installed targeting packs
"/p:NetCoreTargetingPackRoot=" + Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())
};
return args;
}
}
}
|