未验证 提交 51010e5b 编写于 作者: C Chris Sienkiewicz 提交者: GitHub

Msbuild target tests (#44365)

- Multi-target build unit tests
- Add target tests for analyzer config generation
- Fix a bug around invalid metadata
- Fix tests on framework
上级 16eb5237
......@@ -83,13 +83,17 @@ public override bool Execute()
foreach (var item in group)
{
string itemType = item.GetMetadata("ItemType");
string metadataName = item.GetMetadata("MetadataName");
builder.Append("build_metadata.")
.Append(item.GetMetadata("ItemType"))
.Append(".")
.Append(metadataName)
.Append(" = ")
.AppendLine(item.GetMetadata(metadataName));
if (!string.IsNullOrWhiteSpace(itemType) && !string.IsNullOrWhiteSpace(metadataName))
{
builder.Append("build_metadata.")
.Append(itemType)
.Append(".")
.Append(metadataName)
.Append(" = ")
.AppendLine(item.GetMetadata(metadataName));
}
}
}
......
......@@ -107,7 +107,7 @@
<!-- Collect the requested items and remember which metadata is wanted -->
<_GeneratedEditorConfigMetadata Include="@(%(CompilerVisibleItemMetadata.Identity))" Condition="'$(_GeneratedEditorConfigHasItems)' == 'true'">
<ItemType>%(Identity)</ItemType>
<MetadataName>%(MetadataName)</MetadataName>
<MetadataName>%(CompilerVisibleItemMetadata.MetadataName)</MetadataName>
</_GeneratedEditorConfigMetadata>
<!-- Record that we'll write a file, and add it to the editorconfig inputs -->
......
......@@ -474,7 +474,7 @@ public void EditorConfig()
csc = new Csc();
csc.Sources = MSBuildUtil.CreateTaskItems("test.cs", "subdir\\test.cs");
csc.AnalyzerConfigFiles = MSBuildUtil.CreateTaskItems(".editorconfig", "subdir\\.editorconfig");
Assert.Equal(@"/out:test.exe /analyzerconfig:.editorconfig /analyzerconfig:subdir\.editorconfig test.cs subdir\test.cs", csc.GenerateResponseFileContents());
Assert.Equal($@"/out:test.exe /analyzerconfig:.editorconfig /analyzerconfig:subdir\.editorconfig test.cs subdir{Path.DirectorySeparatorChar}test.cs", csc.GenerateResponseFileContents());
csc = new Csc();
csc.Sources = MSBuildUtil.CreateTaskItems("test.cs");
......
......@@ -4,6 +4,7 @@
#nullable enable
using System;
using System.IO;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -41,8 +42,8 @@ public void TestSourceLink()
<Target Name=""_InitializeSourceControlProperties"" BeforeTargets=""InitializeSourceControlInformation"">
<ItemGroup>
<SourceRoot Include=""{root1}"" SourceControl=""git"" SourceLinkUrl=""https://raw.githubusercontent.com/R1/*""/>
<SourceRoot Include=""{root1}sub1\"" SourceControl=""git"" NestedRoot=""sub1"" ContainingRoot=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/M1/*""/>
<SourceRoot Include=""{root1}sub2\"" SourceControl=""git"" NestedRoot=""sub2"" ContainingRoot=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/M2/*""/>
<SourceRoot Include=""{root1}sub1{Path.DirectorySeparatorChar}"" SourceControl=""git"" NestedRoot=""sub1"" ContainingRoot=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/M1/*""/>
<SourceRoot Include=""{root1}sub2{Path.DirectorySeparatorChar}"" SourceControl=""git"" NestedRoot=""sub2"" ContainingRoot=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/M2/*""/>
</ItemGroup>
</Target>
<Target Name=""_GenerateSourceLinkFile""
......@@ -86,8 +87,8 @@ public void TestSourceLink()
{
$@"{root2}: /_1/",
$@"{root1}: /_/",
$@"{root1}sub1\: /_/sub1/",
$@"{root1}sub2\: /_/sub2/",
$@"{root1}sub1{Path.DirectorySeparatorChar}: /_/sub1/",
$@"{root1}sub2{Path.DirectorySeparatorChar}: /_/sub2/",
"true",
$@"{escapedRoot2}=/_1/,{escapedRoot1}=/_/,PreviousPathMap",
"true"
......@@ -124,8 +125,8 @@ public void TestSourceLink()
{
$@"{root2}: {root2}",
$@"{root1}: {root1}",
$@"{root1}sub1\: {root1}sub1\",
$@"{root1}sub2\: {root1}sub2\",
$@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}",
$@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}",
@"",
$@""
});
......@@ -133,8 +134,8 @@ public void TestSourceLink()
AssertEx.AssertEqualToleratingWhitespaceDifferences(
$@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," +
$@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," +
$@"[{root1}sub1\]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2\]=[https://raw.githubusercontent.com/M2/*]",
$@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]",
File.ReadAllText(sourceLinkJsonPath));
// deterministic local build:
......@@ -160,8 +161,8 @@ public void TestSourceLink()
{
$@"{root2}: {root2}",
$@"{root1}: {root1}",
$@"{root1}sub1\: {root1}sub1\",
$@"{root1}sub2\: {root1}sub2\",
$@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}",
$@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}",
@"",
$@""
});
......@@ -169,8 +170,8 @@ public void TestSourceLink()
AssertEx.AssertEqualToleratingWhitespaceDifferences(
$@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," +
$@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," +
$@"[{root1}sub1\]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2\]=[https://raw.githubusercontent.com/M2/*]",
$@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]",
File.ReadAllText(sourceLinkJsonPath));
// DeterministicSourcePaths override:
......@@ -196,8 +197,8 @@ public void TestSourceLink()
{
$@"{root2}: {root2}",
$@"{root1}: {root1}",
$@"{root1}sub1\: {root1}sub1\",
$@"{root1}sub2\: {root1}sub2\",
$@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}",
$@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}",
@"false",
$@""
});
......@@ -205,8 +206,8 @@ public void TestSourceLink()
AssertEx.AssertEqualToleratingWhitespaceDifferences(
$@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," +
$@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," +
$@"[{root1}sub1\]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2\]=[https://raw.githubusercontent.com/M2/*]",
$@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," +
$@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]",
File.ReadAllText(sourceLinkJsonPath));
// SourceControlInformationFeatureSupported = false:
......@@ -322,9 +323,9 @@ public void InitializeSourceRootMappedPathsReturnsSourceMap(bool deterministicSo
},
expectedResults: new[]
{
@"X\",
@"Y\",
@"Z\",
$"X{Path.DirectorySeparatorChar}",
$"Y{Path.DirectorySeparatorChar}",
$"Z{Path.DirectorySeparatorChar}",
});
}
......
......@@ -34,8 +34,8 @@ public void GlobalPropertyIsGeneratedIfEmpty()
[Fact]
public void PropertiesAreGeneratedInGlobalSection()
{
TaskItem property1 = new TaskItem("Property1", new Dictionary<string, string> { { "Value", "abc123" } });
TaskItem property2 = new TaskItem("Property2", new Dictionary<string, string> { { "Value", "def456" } });
ITaskItem property1 = MSBuildUtil.CreateTaskItem("Property1", new Dictionary<string, string> { { "Value", "abc123" } });
ITaskItem property2 = MSBuildUtil.CreateTaskItem("Property2", new Dictionary<string, string> { { "Value", "def456" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -54,7 +54,7 @@ public void PropertiesAreGeneratedInGlobalSection()
[Fact]
public void ItemMetaDataCreatesSection()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -74,9 +74,9 @@ public void ItemMetaDataCreatesSection()
[Fact]
public void MutlipleItemMetaDataCreatesSections()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
TaskItem item2 = new TaskItem("c:\\file2.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
TaskItem item3 = new TaskItem("c:\\file3.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "ghi789" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
ITaskItem item2 = MSBuildUtil.CreateTaskItem("c:/file2.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
ITaskItem item3 = MSBuildUtil.CreateTaskItem("c:/file3.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "ghi789" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -102,8 +102,8 @@ public void MutlipleItemMetaDataCreatesSections()
[Fact]
public void DuplicateItemSpecsAreCombinedInSections()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
TaskItem item2 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
ITaskItem item2 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -124,7 +124,7 @@ public void DuplicateItemSpecsAreCombinedInSections()
[Fact]
public void ItemIsMissingRequestedMetadata()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -144,9 +144,9 @@ public void ItemIsMissingRequestedMetadata()
[Fact]
public void ItemIsMissingRequiredMetadata()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { });
TaskItem item2 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" } });
TaskItem item3 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "MetadataName", "ToRetrieve" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { });
ITaskItem item2 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" } });
ITaskItem item3 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "MetadataName", "ToRetrieve" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -159,22 +159,19 @@ public void ItemIsMissingRequiredMetadata()
Assert.Equal(@"is_global = true
[c:/file1.cs]
build_metadata.. =
build_metadata.Compile. =
build_metadata..ToRetrieve =
", result);
}
[Fact]
public void PropertiesAreGeneratedBeforeItems()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
TaskItem item2 = new TaskItem("c:\\file2.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
TaskItem item3 = new TaskItem("c:\\file3.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "ghi789" } });
TaskItem item4 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "jkl012" } });
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
ITaskItem item2 = MSBuildUtil.CreateTaskItem("c:/file2.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
ITaskItem item3 = MSBuildUtil.CreateTaskItem("c:/file3.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "ghi789" } });
ITaskItem item4 = MSBuildUtil.CreateTaskItem("c:/file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFiles" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "jkl012" } });
TaskItem property1 = new TaskItem("Property1", new Dictionary<string, string> { { "Value", "abc123" } });
TaskItem property2 = new TaskItem("Property2", new Dictionary<string, string> { { "Value", "def456" } });
ITaskItem property1 = MSBuildUtil.CreateTaskItem("Property1", new Dictionary<string, string> { { "Value", "abc123" } });
ITaskItem property2 = MSBuildUtil.CreateTaskItem("Property2", new Dictionary<string, string> { { "Value", "def456" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -218,7 +215,7 @@ public void ItemIsNotFullyQualifiedPath()
// MSBuild will convert the above relative paths to absolute paths based on the current location.
// We replicate that behavior here to test we get the expected full paths
string executingLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).Replace('\\', '/');
string executingLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)?.Replace('\\', '/') ?? string.Empty;
string expectedPath1 = $"{executingLocation}/file1.cs";
string expectedPath2 = $"{executingLocation}/subDir/file2.cs";
string expectedPath3 = $"{executingLocation}/someDir/otherDir/file3.cs";
......@@ -239,8 +236,8 @@ public void ItemIsNotFullyQualifiedPath()
[Fact]
public void ItemsWithDifferentRelativeButSameFullPathAreCombined()
{
TaskItem item1 = new TaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
TaskItem item2 = new TaskItem("c:\\someDir\\..\\file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
TaskItem item1 = new TaskItem("file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
TaskItem item2 = new TaskItem("someDir\\..\\file1.cs", new Dictionary<string, string> { { "ItemType", "AdditionalFile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "def456" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
......@@ -250,9 +247,14 @@ public void ItemsWithDifferentRelativeButSameFullPathAreCombined()
var result = configTask.ConfigFileContents;
// MSBuild will convert the above relative paths to absolute paths based on the current location.
// We replicate that behavior here to test we get the expected full paths
string executingLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)?.Replace('\\', '/') ?? string.Empty;
string expectedPath = $"{executingLocation}/file1.cs";
Assert.Equal($@"is_global = true
[c:/file1.cs]
[{expectedPath}]
build_metadata.Compile.ToRetrieve = abc123
build_metadata.AdditionalFile.ToRetrieve = def456
", result);
......@@ -300,6 +302,26 @@ public void PropertiesWithNewLines()
values
build_property.Property2 = def456
", result);
}
[ConditionalFact(typeof(WindowsOnly))]
public void ItemMetadataPathIsAdjustedOnWindows()
{
ITaskItem item1 = MSBuildUtil.CreateTaskItem("c:\\file1.cs", new Dictionary<string, string> { { "ItemType", "Compile" }, { "MetadataName", "ToRetrieve" }, { "ToRetrieve", "abc123" } });
GenerateMSBuildEditorConfig configTask = new GenerateMSBuildEditorConfig()
{
MetadataItems = new[] { item1 }
};
configTask.Execute();
var result = configTask.ConfigFileContents;
Assert.Equal(@"is_global = true
[c:/file1.cs]
build_metadata.Compile.ToRetrieve = abc123
", result);
}
}
......
......@@ -4,6 +4,7 @@
#nullable enable
#if NET472
using System;
using System.Collections.Generic;
using System.Diagnostics;
......@@ -122,7 +123,7 @@ private void VerifyResultAndOutput(ProcessResult result, TempDirectory path, str
{ "HelloSolution.sln",
@"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
\u0023 Visual Studio 2010
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""HelloProj"", ""HelloProj.csproj"", ""{7F4CCBA2-1184-468A-BF3D-30792E4E8003}""
EndProject
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""HelloLib"", ""HelloLib.csproj"", ""{C1170A4A-80CF-4B4F-AA58-2FAEA9158D31}""
......@@ -428,7 +429,7 @@ public void SimpleMSBuild()
{ "HelloSolution.sln",
@"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
\u0023 Visual Studio 2010
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""HelloLib"", ""HelloLib.csproj"", ""{C1170A4A-80CF-4B4F-AA58-2FAEA9158D31}""
EndProject
Project(""{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"") = ""VBLib"", ""VBLib.vbproj"", ""{F21C894B-28E5-4212-8AF7-C8E0E5455737}""
......@@ -620,7 +621,7 @@ public void SolutionWithPunctuation()
var slnFile = testDir.CreateFile("Console;!@(goo)'^(Application1.sln").WriteAllText(
@"
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2005
\u0023 Visual Studio 2005
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Cons.ole;!@(goo)'^(Application1"", ""Console;!@(goo)'^(Application1\Cons.ole;!@(goo)'^(Application1.csproj"", ""{770F2381-8C39-49E9-8C96-0538FA4349A7}""
EndProject
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Class;!@(goo)'^(Library1"", ""Class;!@(goo)'^(Library1\Class;!@(goo)'^(Library1.csproj"", ""{0B4B78CC-C752-43C2-BE9A-319D20216129}""
......@@ -786,3 +787,4 @@ public class Class1
}
}
}
#endif
......@@ -5,7 +5,7 @@
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.CodeAnalysis.BuildTasks.UnitTests</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFramework>net472</TargetFramework>
<TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
<Nullable>enable</Nullable>
<!-- Multiple test failures -->
......@@ -20,14 +20,18 @@
<ProjectReference Include="..\Portable\Microsoft.CodeAnalysis.csproj" />
<ProjectReference Include="..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
</ItemGroup>
<ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<Reference Include="Microsoft.Build.Engine" />
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Collections.Immutable" Version="$(SystemCollectionsImmutableVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
<PackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Framework" Version="$(MicrosoftBuildFrameworkVersion)" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(MicrosoftBuildTasksCoreVersion)" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="$(SystemThreadingTasksDataflowVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
......
// 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.
#nullable enable
// uncomment the below define to dump binlogs of each test
// #define DUMP_MSBUILD_BIN_LOG
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Xunit;
namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests
{
public class TargetTests
{
[Fact]
public void GenerateEditorConfigShouldNotRunWhenNoPropertiesOrMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFileShouldRun", GetTestLoggers());
var shouldRun = instance.GetPropertyValue("_GeneratedEditorConfigShouldRun");
var hasItems = instance.GetPropertyValue("_GeneratedEditorConfigHasItems");
Assert.True(runSuccess);
Assert.NotEqual("true", shouldRun);
Assert.NotEqual("true", hasItems);
}
[Fact]
public void GenerateEditorConfigShouldRunWhenPropertiesRequested()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<CompilerVisibleProperty Include=""prop"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFileShouldRun", GetTestLoggers());
var shouldRun = instance.GetPropertyValue("_GeneratedEditorConfigShouldRun");
var hasItems = instance.GetPropertyValue("_GeneratedEditorConfigHasItems");
Assert.True(runSuccess);
Assert.Equal("true", shouldRun);
Assert.NotEqual("true", hasItems);
}
[Fact]
public void GenerateEditorConfigShouldRunWhenMetadataRequested()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<CompilerVisibleItemMetadata Include=""item"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFileShouldRun", GetTestLoggers());
var shouldRun = instance.GetPropertyValue("_GeneratedEditorConfigShouldRun");
var hasItems = instance.GetPropertyValue("_GeneratedEditorConfigHasItems");
Assert.True(runSuccess);
Assert.Equal("true", shouldRun);
Assert.Equal("true", hasItems);
}
[Fact]
public void GenerateEditorConfigShouldRunWhenPropertiesAndMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<CompilerVisibleProperty Include=""prop"" />
<CompilerVisibleItemMetadata Include=""item"" Metadata=""meta"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFileShouldRun", GetTestLoggers());
var shouldRun = instance.GetPropertyValue("_GeneratedEditorConfigShouldRun");
var hasItems = instance.GetPropertyValue("_GeneratedEditorConfigHasItems");
Assert.True(runSuccess);
Assert.Equal("true", shouldRun);
Assert.Equal("true", hasItems);
}
[Fact]
public void GenerateEditorConfigCanBeDisabled()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<PropertyGroup>
<GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile>
</PropertyGroup>
<ItemGroup>
<CompilerVisibleProperty Include=""prop"" />
<CompilerVisibleItemMetadata Include=""item"" Metadata=""meta"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFileShouldRun", GetTestLoggers());
var shouldRun = instance.GetPropertyValue("_GeneratedEditorConfigShouldRun");
var hasItems = instance.GetPropertyValue("_GeneratedEditorConfigHasItems");
Assert.True(runSuccess);
Assert.NotEqual("true", shouldRun);
Assert.Equal("true", hasItems);
}
[Fact]
public void GenerateEditorConfigCoreEvaluatesProperties()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<PropertyGroup>
<ValueToGet>abc</ValueToGet>
</PropertyGroup>
<ItemGroup>
<CompilerVisibleProperty Include=""ValueToGet"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigProperty");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigProperty", item.ItemType);
Assert.Single(item.Metadata);
var metadata = item.Metadata.Single();
Assert.Equal("Value", metadata.Name);
Assert.Equal("abc", metadata.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreEvaluatesDynamicProperties()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<PropertyGroup>
<RealValue>def</RealValue>
<ValueToGet>$(RealValue)</ValueToGet>
</PropertyGroup>
<ItemGroup>
<CompilerVisibleProperty Include=""ValueToGet"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigProperty");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigProperty", item.ItemType);
Assert.Single(item.Metadata);
var metadata = item.Metadata.Single();
Assert.Equal("Value", metadata.Name);
Assert.Equal("def", metadata.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreHandlesMissingProperties()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<CompilerVisibleProperty Include=""ValueToGet"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigProperty");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigProperty", item.ItemType);
Assert.Single(item.Metadata);
var metadata = item.Metadata.Single();
Assert.Equal("Value", metadata.Name);
Assert.Equal("", metadata.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreEvaluatesMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<Compile Include=""file1.cs"" CustomMeta=""abc"" />
</ItemGroup>
<ItemGroup>
<CompilerVisibleItemMetadata Include=""Compile"" MetadataName=""CustomMeta"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigMetadata");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigMetadata", item.ItemType);
var itemType = item.Metadata.SingleOrDefault(m => m.Name == "ItemType");
Assert.NotNull(itemType);
Assert.Equal("Compile", itemType.EvaluatedValue);
var metaName = item.Metadata.SingleOrDefault(m => m.Name == "MetadataName");
Assert.NotNull(metaName);
Assert.Equal("CustomMeta", metaName.EvaluatedValue);
var customMeta = item.Metadata.SingleOrDefault(m => m.Name == metaName.EvaluatedValue);
Assert.NotNull(customMeta);
Assert.Equal("abc", customMeta.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreEvaluatesDynamicMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<PropertyGroup>
<DynamicValue>abc</DynamicValue>
</PropertyGroup>
<ItemGroup>
<Compile Include=""file1.cs"" CustomMeta=""$(DynamicValue)"" />
</ItemGroup>
<ItemGroup>
<CompilerVisibleItemMetadata Include=""Compile"" MetadataName=""CustomMeta"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigMetadata");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigMetadata", item.ItemType);
var itemType = item.Metadata.SingleOrDefault(m => m.Name == "ItemType");
Assert.NotNull(itemType);
Assert.Equal("Compile", itemType.EvaluatedValue);
var metaName = item.Metadata.SingleOrDefault(m => m.Name == "MetadataName");
Assert.NotNull(metaName);
Assert.Equal("CustomMeta", metaName.EvaluatedValue);
var customMeta = item.Metadata.SingleOrDefault(m => m.Name == metaName.EvaluatedValue);
Assert.NotNull(customMeta);
Assert.Equal("abc", customMeta.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreHandlesMissingMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<Compile Include=""file1.cs"" />
</ItemGroup>
<ItemGroup>
<CompilerVisibleItemMetadata Include=""Compile"" MetadataName=""CustomMeta"" />
<CompilerVisibleItemMetadata Include=""Compile2"" MetadataName=""CustomMeta"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigMetadata");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigMetadata", item.ItemType);
var itemType = item.Metadata.SingleOrDefault(m => m.Name == "ItemType");
Assert.NotNull(itemType);
Assert.Equal("Compile", itemType.EvaluatedValue);
var metaName = item.Metadata.SingleOrDefault(m => m.Name == "MetadataName");
Assert.NotNull(metaName);
Assert.Equal("CustomMeta", metaName.EvaluatedValue);
}
[Fact]
public void GenerateEditorConfigCoreHandlesMalformedCompilerVisibleItemMetadata()
{
XmlReader xmlReader = XmlReader.Create(new StringReader($@"
<Project>
<Import Project=""Microsoft.Managed.Core.targets"" />
<ItemGroup>
<Compile Include=""file1.cs"" />
</ItemGroup>
<ItemGroup>
<CompilerVisibleItemMetadata Include=""Compile"" />
</ItemGroup>
</Project>
"));
var instance = CreateProjectInstance(xmlReader);
bool runSuccess = instance.Build(target: "GenerateMSBuildEditorConfigFile", GetTestLoggers());
Assert.True(runSuccess);
var items = instance.GetItems("_GeneratedEditorConfigMetadata");
Assert.Single(items);
var item = items.Single();
Assert.Equal("_GeneratedEditorConfigMetadata", item.ItemType);
var itemType = item.Metadata.SingleOrDefault(m => m.Name == "ItemType");
Assert.NotNull(itemType);
Assert.Equal("Compile", itemType.EvaluatedValue);
var metaName = item.Metadata.SingleOrDefault(m => m.Name == "MetadataName");
Assert.NotNull(metaName);
Assert.Equal("", metaName.EvaluatedValue);
}
private ProjectInstance CreateProjectInstance(XmlReader reader)
{
Project proj = new Project(reader);
// add a dummy prepare for build target
proj.Xml.AddTarget("PrepareForBuild");
// create a dummy WriteLinesToFile task
var usingTask = proj.Xml.AddUsingTask("WriteLinesToFile", string.Empty, Assembly.GetExecutingAssembly().FullName);
usingTask.TaskFactory = nameof(DummyTaskFactory);
var taskParams = usingTask.AddParameterGroup();
taskParams.AddParameter("Lines", "", "", "System.String[]");
taskParams.AddParameter("File", "", "", "System.String");
taskParams.AddParameter("Overwrite", "", "", "System.Boolean");
taskParams.AddParameter("WriteOnlyWhenDifferent", "", "", "System.Boolean");
// create an instance and return it
return proj.CreateProjectInstance();
}
private ILogger[] GetTestLoggers([CallerMemberName] string callerName = "")
{
#if DUMP_MSBUILD_BIN_LOG
return new ILogger[]
{
new BinaryLogger()
{
Parameters = callerName + ".binlog"
}
};
#else
return Array.Empty<ILogger>();
#endif
}
}
/// <summary>
/// Task factory that creates empty tasks for testing
/// </summary>
/// <remarks>
/// Replace any task with a dummy task by adding a <c>UsingTask</c>
/// <code>
/// <UsingTask TaskName="[TaskToReplace]" TaskFactory="DummyTaskFactory">
/// <ParameterGroup>
/// <Param1 ParameterType="[Type]" />
/// </ParameterGroup>
/// </UsingTask>
/// </code>
///
/// You can specify the parameters the task should have via a <c>ParameterGroup</c>
/// These should match the task you are replacing.
/// </remarks>
public sealed class DummyTaskFactory : ITaskFactory
{
public string FactoryName { get => "DummyTaskFactory"; }
public Type TaskType { get => typeof(DummyTaskFactory); }
private TaskPropertyInfo[]? _props;
public void CleanupTask(ITask task) { }
public ITask CreateTask(IBuildEngine taskFactoryLoggingHost) => new DummyTask();
public TaskPropertyInfo[]? GetTaskParameters() => _props;
public bool Initialize(string taskName, IDictionary<string, TaskPropertyInfo> parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost)
{
_props = parameterGroup.Values.ToArray();
return true;
}
private class DummyTask : IGeneratedTask
{
public IBuildEngine? BuildEngine { get; set; }
public ITaskHost? HostObject { get; set; }
public bool Execute() => true;
public object GetPropertyValue(TaskPropertyInfo property) => null!;
public void SetPropertyValue(TaskPropertyInfo property, object value) { }
}
}
}
......@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
......@@ -66,15 +67,16 @@ private static string GetSdkPath(string dotnetInstallDir, string version)
static DotNetSdkTestBase()
{
s_dotnetExeName = "dotnet" + (Path.DirectorySeparatorChar == '/' ? "" : ".exe");
s_dotnetSdkVersion = typeof(DotNetSdkTests).Assembly.GetCustomAttribute<DotNetSdkVersionAttribute>().Version;
s_dotnetSdkVersion = typeof(DotNetSdkTests).Assembly.GetCustomAttribute<DotNetSdkVersionAttribute>()?.Version
?? throw new InvalidOperationException($"Couldn't find {nameof(DotNetSdkVersionAttribute)}");
bool isMatchingDotNetInstance(string dotnetDir)
static bool isMatchingDotNetInstance(string? dotnetDir)
=> dotnetDir != null && File.Exists(Path.Combine(dotnetDir, s_dotnetExeName)) && Directory.Exists(GetSdkPath(dotnetDir, s_dotnetSdkVersion));
var dotnetInstallDir = Environment.GetEnvironmentVariable("DOTNET_INSTALL_DIR");
if (!isMatchingDotNetInstance(dotnetInstallDir))
{
dotnetInstallDir = Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator).FirstOrDefault(isMatchingDotNetInstance);
dotnetInstallDir = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator).FirstOrDefault(isMatchingDotNetInstance);
}
if (dotnetInstallDir != null)
......@@ -137,11 +139,12 @@ bool isMatchingDotNetInstance(string dotnetDir)
public DotNetSdkTestBase()
{
Assert.True(s_dotnetInstallDir != null, $"SDK not found. Use {nameof(ConditionalFactAttribute)}(typeof({nameof(DotNetSdkAvailable)})) to skip the test if the SDK is not found.");
Assert.True(s_dotnetInstallDir is object, $"SDK not found. Use {nameof(ConditionalFactAttribute)}(typeof({nameof(DotNetSdkAvailable)})) to skip the test if the SDK is not found.");
Debug.Assert(s_dotnetInstallDir is object);
DotNetPath = Path.Combine(s_dotnetInstallDir, s_dotnetExeName);
var testBinDirectory = Path.GetDirectoryName(typeof(DotNetSdkTests).Assembly.Location);
var sdksDir = Path.Combine(s_dotnetSdkPath, "Sdks");
var testBinDirectory = Path.GetDirectoryName(typeof(DotNetSdkTests).Assembly.Location) ?? string.Empty;
var sdksDir = Path.Combine(s_dotnetSdkPath ?? string.Empty, "Sdks");
ProjectName = "test";
ProjectFileName = ProjectName + ".csproj";
......
......@@ -27,5 +27,17 @@ public static ITaskItem CreateTaskItem(string fileName)
taskItem.Setup(x => x.ItemSpec).Returns(fileName);
return taskItem.Object;
}
public static ITaskItem CreateTaskItem(string fileName, Dictionary<string, string> metadata)
{
var taskItem = new Mock<ITaskItem>(MockBehavior.Strict);
taskItem.Setup(x => x.ItemSpec).Returns(fileName);
taskItem.Setup(x => x.GetMetadata(It.IsAny<string>())).Returns<string>(s => s switch
{
"FullPath" => fileName,
_ => metadata.ContainsKey(s) ? metadata[s] : string.Empty
});
return taskItem.Object;
}
}
}
......@@ -5,6 +5,7 @@
#nullable enable
using System;
using System.IO;
using Microsoft.CodeAnalysis.BuildTasks;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -437,7 +438,7 @@ public void EditorConfig()
vbc = new Vbc();
vbc.Sources = MSBuildUtil.CreateTaskItems("test.vb", "subdir\\test.vb");
vbc.AnalyzerConfigFiles = MSBuildUtil.CreateTaskItems(".editorconfig", "subdir\\.editorconfig");
Assert.Equal(@"/optionstrict:custom /out:test.exe /analyzerconfig:.editorconfig /analyzerconfig:subdir\.editorconfig test.vb subdir\test.vb", vbc.GenerateResponseFileContents());
Assert.Equal(@$"/optionstrict:custom /out:test.exe /analyzerconfig:.editorconfig /analyzerconfig:subdir\.editorconfig test.vb subdir{Path.DirectorySeparatorChar}test.vb", vbc.GenerateResponseFileContents());
vbc = new Vbc();
vbc.Sources = MSBuildUtil.CreateTaskItems("test.vb");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册