/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Core/MSBuildTaskTests/DotNetSdkTests.cs
661 строка
27 KB
Tomáš Matoušek
Revert "Revert "Update VSSDK to 18.9.496-Preview"" (#84403)
09 июл 2026, 02:44
Не верифицирован
09 июл 2026, 02:44
16f6817
Код
Авторство
О чём код?
// 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; using System.Collections.Generic; using System.IO; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests { public class DotNetSdkTests : DotNetSdkTestBase { public DotNetSdkTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } [ConditionalFact(typeof(DotNetSdkAvailable), AlwaysSkip = "https://github.com/dotnet/roslyn/issues/46304")] [WorkItem(22835, "https://github.com/dotnet/roslyn/issues/22835")] public void TestSourceLink() { var sourcePackageDir = Temp.CreateDirectory().CreateDirectory("a=b, c"); var libFile = sourcePackageDir.CreateFile("lib.cs").WriteAllText("class Lib { public void M() { } }"); var root1 = Path.GetFullPath(ProjectDir.Path + Path.DirectorySeparatorChar); var root2 = Path.GetFullPath(sourcePackageDir.Path + Path.DirectorySeparatorChar); var root3 = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); root3 ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); root3 += Path.DirectorySeparatorChar; var escapedRoot1 = root1.Replace(",", ",,").Replace("=", "=="); var escapedRoot2 = root2.Replace(",", ",,").Replace("=", "=="); var escapedRoot3 = root3.Replace(",", ",,").Replace("=", "=="); var sourceLinkJsonPath = Path.Combine(ObjDir.Path, ProjectName + ".sourcelink.json"); var sourcePackageProps = $@" <ItemGroup> <Compile Include=""{libFile.Path}"" Link=""Lib.cs"" /> <SourceRoot Include=""{root2}"" SourceLinkUrl=""https://raw.githubusercontent.com/Source/Package/*""/> </ItemGroup> "; var sourceLinkPackageTargets = $@" <PropertyGroup> <SourceLink>{sourceLinkJsonPath}</SourceLink> </PropertyGroup> <Target Name=""_InitializeSourceControlProperties"" BeforeTargets=""InitializeSourceControlInformation""> <ItemGroup> <SourceRoot Include=""{root1}"" SourceControl=""git"" SourceLinkUrl=""https://raw.githubusercontent.com/R1/*""/> <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"" DependsOnTargets=""InitializeSourceRootMappedPaths"" BeforeTargets=""CoreCompile"" Outputs=""$(SourceLink)""> <WriteLinesToFile File=""$(SourceLink)"" Lines=""@(SourceRoot->'[%(MappedPath)]=[%(SourceLinkUrl)]', ',')"" Overwrite=""true"" Encoding=""UTF-8"" /> <ItemGroup> <FileWrites Include=""$(SourceLink)"" /> </ItemGroup> </Target> "; // deterministic CI build: VerifyValues( customProps: $@" <PropertyGroup> <SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported> <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> <PathMap>PreviousPathMap</PathMap> </PropertyGroup> {sourcePackageProps}", customTargets: sourceLinkPackageTargets, targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)", "$(SourceRootMappedPathsFeatureSupported)" }, expectedResults: new[] { $@"{root3}: /_1/", $@"{root2}: /_2/", $@"{root1}: /_/", $@"{root1}sub1{Path.DirectorySeparatorChar}: /_/sub1/", $@"{root1}sub2{Path.DirectorySeparatorChar}: /_/sub2/", "true", $@"{escapedRoot3}=/_1/,{escapedRoot2}=/_2/,{escapedRoot1}=/_/,PreviousPathMap", "true" }); AssertEx.AssertEqualToleratingWhitespaceDifferences( "[/_1/]=[]," + "[/_2/]=[https://raw.githubusercontent.com/Source/Package/*]," + "[/_/]=[https://raw.githubusercontent.com/R1/*]," + "[/_/sub1/]=[https://raw.githubusercontent.com/M1/*]," + "[/_/sub2/]=[https://raw.githubusercontent.com/M2/*]", File.ReadAllText(sourceLinkJsonPath)); // non-deterministic CI build: VerifyValues( customProps: $@" <PropertyGroup> <SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported> <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> <Deterministic>false</Deterministic> </PropertyGroup> {sourcePackageProps}", customTargets: sourceLinkPackageTargets, targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)" }, expectedResults: new[] { $@"{root3}: {root3}", $@"{root2}: {root2}", $@"{root1}: {root1}", $@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}", $@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}", @"", $@"" }); AssertEx.AssertEqualToleratingWhitespaceDifferences( $@"[{root3}]=[]," + $@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," + $@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," + $@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," + $@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]", File.ReadAllText(sourceLinkJsonPath)); // deterministic local build: VerifyValues( customProps: $@" <PropertyGroup> <SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported> <ContinuousIntegrationBuild>false</ContinuousIntegrationBuild> </PropertyGroup> {sourcePackageProps}", customTargets: sourceLinkPackageTargets, targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)" }, expectedResults: new[] { $@"{root3}: {root3}", $@"{root2}: {root2}", $@"{root1}: {root1}", $@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}", $@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}", @"", $@"" }); AssertEx.AssertEqualToleratingWhitespaceDifferences( $@"[{root3}]=[]," + $@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," + $@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," + $@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," + $@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]", File.ReadAllText(sourceLinkJsonPath)); // DeterministicSourcePaths override: VerifyValues( customProps: $@" <PropertyGroup> <SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported> <DeterministicSourcePaths>false</DeterministicSourcePaths> </PropertyGroup> {sourcePackageProps}", customTargets: sourceLinkPackageTargets, targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)" }, expectedResults: new[] { $@"{root3}: {root3}", $@"{root2}: {root2}", $@"{root1}: {root1}", $@"{root1}sub1{Path.DirectorySeparatorChar}: {root1}sub1{Path.DirectorySeparatorChar}", $@"{root1}sub2{Path.DirectorySeparatorChar}: {root1}sub2{Path.DirectorySeparatorChar}", @"false", $@"" }); AssertEx.AssertEqualToleratingWhitespaceDifferences( $@"[{root3}]=[]," + $@"[{root2}]=[https://raw.githubusercontent.com/Source/Package/*]," + $@"[{root1}]=[https://raw.githubusercontent.com/R1/*]," + $@"[{root1}sub1{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M1/*]," + $@"[{root1}sub2{Path.DirectorySeparatorChar}]=[https://raw.githubusercontent.com/M2/*]", File.ReadAllText(sourceLinkJsonPath)); // SourceControlInformationFeatureSupported = false: VerifyValues( customProps: $@" <PropertyGroup> <DeterministicSourcePaths>true</DeterministicSourcePaths> </PropertyGroup> <ItemGroup> <SourceRoot Include=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/R1/*"" /> </ItemGroup> {sourcePackageProps}", customTargets: $@" <PropertyGroup> <SourceControlInformationFeatureSupported>false</SourceControlInformationFeatureSupported> </PropertyGroup> {sourceLinkPackageTargets}", targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)" }, expectedResults: new[] { $@"{root3}: /_/", $@"{root1}: /_1/", $@"{root2}: /_2/", @"true", $@"{escapedRoot3}=/_/,{escapedRoot1}=/_1/,{escapedRoot2}=/_2/," }); AssertEx.AssertEqualToleratingWhitespaceDifferences( $@"[/_/]=[]," + $@"[/_1/]=[https://raw.githubusercontent.com/R1/*]," + $@"[/_2/]=[https://raw.githubusercontent.com/Source/Package/*]", File.ReadAllText(sourceLinkJsonPath)); // No SourceLink package: VerifyValues( customProps: $@" <PropertyGroup> <DeterministicSourcePaths>true</DeterministicSourcePaths> </PropertyGroup> <ItemGroup> <SourceRoot Include=""{root1}"" SourceLinkUrl=""https://raw.githubusercontent.com/R1/*"" /> </ItemGroup> {sourcePackageProps}", customTargets: @" <PropertyGroup> <SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported> </PropertyGroup> ", targets: new[] { "CoreCompile" }, expressions: new[] { "@(SourceRoot->'%(Identity): %(MappedPath)')", "$(DeterministicSourcePaths)", "$(PathMap)" }, expectedResults: new[] { $@"{root3}: /_/", $@"{root1}: /_1/", $@"{root2}: /_2/", @"true", $@"{escapedRoot3}=/_/,{escapedRoot1}=/_1/,{escapedRoot2}=/_2/," }); AssertEx.AssertEqualToleratingWhitespaceDifferences( $@"[/_/]=[]," + $@"[/_1/]=[https://raw.githubusercontent.com/R1/*]," + $@"[/_2/]=[https://raw.githubusercontent.com/Source/Package/*]", File.ReadAllText(sourceLinkJsonPath)); } [ConditionalTheory(typeof(DotNetSdkAvailable))] [CombinatorialData] [WorkItem(43476, "https://github.com/dotnet/roslyn/issues/43476")] [WorkItem(82112, "https://github.com/dotnet/roslyn/issues/82112")] public void InitializeSourceRootMappedPathsReturnsSourceMap(bool deterministicSourcePaths) { ProjectDir.CreateFile("Project2.csproj").WriteAllText($@" <Project Sdk='Microsoft.NET.Sdk'> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <DeterministicSourcePaths>{deterministicSourcePaths}</DeterministicSourcePaths> </PropertyGroup> <ItemGroup> <SourceRoot Include=""X\""/> <SourceRoot Include=""Y\"" ContainingRoot=""X\"" NestedRoot=""A""/> <SourceRoot Include=""Z\"" ContainingRoot=""X\"" NestedRoot=""B""/> </ItemGroup> </Project> "); VerifyValues( customProps: $@" <ItemGroup> <ProjectReference Include=""Project2.csproj"" Targets=""InitializeSourceRootMappedPaths"" OutputItemType=""ReferencedProjectSourceRoots"" ReferenceOutputAssembly=""false"" /> </ItemGroup> ", customTargets: null, targets: new[] { "ResolveProjectReferences;_BeforeVBCSCoreCompile" }, expressions: new[] { "@(ReferencedProjectSourceRoots)", }, expectedResults: new[] { // SourceRoot items are canonicalized to absolute paths by the MapSourceRoots task // invoked from the InitializeSourceRootMappedPaths target. Path.GetFullPath(Path.Combine(ProjectDir.Path, "X")) + Path.DirectorySeparatorChar, Path.GetFullPath(Path.Combine(ProjectDir.Path, "Y")) + Path.DirectorySeparatorChar, Path.GetFullPath(Path.Combine(ProjectDir.Path, "Z")) + Path.DirectorySeparatorChar, }); } /// <summary> /// Validates dependencies of _BeforeVBCSCoreCompile target. /// </summary> [ConditionalFact(typeof(DotNetSdkAvailable))] public void BeforeVBCSCoreCompileDependencies() { VerifyValues( customProps: $@" <ItemGroup> <ReferencePath Include=""A"" /> </ItemGroup>", customTargets: null, targets: new[] { "_BeforeVBCSCoreCompile" }, expressions: new[] { "@(ReferencePathWithRefAssemblies)", }, expectedResults: new[] { "A", }); } [ConditionalFact(typeof(DotNetSdkAvailable))] public void ClearEmbedInteropTypes() { VerifyValues( customProps: $@" <PropertyGroup> <TargetingClr2Framework>true</TargetingClr2Framework> </PropertyGroup> <ItemGroup> <ReferencePathWithRefAssemblies Include=""A"" EmbedInteropTypes=""false""/> <ReferencePathWithRefAssemblies Include=""B"" EmbedInteropTypes=""true""/> </ItemGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(ReferencePathWithRefAssemblies->'EmbedInteropTypes=`%(EmbedInteropTypes)`')", }, expectedResults: new[] { "EmbedInteropTypes=``", "EmbedInteropTypes=``" }); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverEditorConfigFiles() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var subdir = ProjectDir.CreateDirectory("subdir"); var srcFile2 = subdir.CreateFile("lib2.cs").WriteAllText("class D { }"); var editorConfigFile2 = subdir.CreateFile(".editorconfig").WriteAllText(@"[*.cs] some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { Path.Combine(ProjectDir.Path, ".editorconfig"), editorConfigFile2.Path })); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverEditorConfigFilesCanBeDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var subdir = ProjectDir.CreateDirectory("subdir"); var srcFile2 = subdir.CreateFile("lib2.cs").WriteAllText("class D { }"); var editorConfigFile2 = subdir.CreateFile(".editorconfig").WriteAllText(@"[*.cs] some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <DiscoverEditorConfigFiles>false</DiscoverEditorConfigFiles> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { "" }, findEditorConfigs: false)); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFiles() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var globalConfigFile = ProjectDir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); var subdir = ProjectDir.CreateDirectory("subdir"); var srcFile2 = subdir.CreateFile("lib2.cs").WriteAllText("class D { }"); var globalConfigFile2 = subdir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { Path.Combine(ProjectDir.Path, ".editorconfig"), globalConfigFile.Path, globalConfigFile2.Path })); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFilesCanBeDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var globalConfigFile = ProjectDir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); var subdir = ProjectDir.CreateDirectory("subdir"); var srcFile2 = subdir.CreateFile("lib2.cs").WriteAllText("class D { }"); var globalConfigFile2 = subdir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <DiscoverGlobalAnalyzerConfigFiles>false</DiscoverGlobalAnalyzerConfigFiles> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { Path.Combine(ProjectDir.Path, ".editorconfig"), }, findGlobalConfigs: false)); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFilesWhenEditorConfigDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var globalConfigFile = ProjectDir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); var subdir = ProjectDir.CreateDirectory("subdir"); var srcFile2 = subdir.CreateFile("lib2.cs").WriteAllText("class D { }"); var globalConfigFile2 = subdir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <DiscoverEditorConfigFiles>false</DiscoverEditorConfigFiles> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { globalConfigFile.Path, globalConfigFile2.Path }, findEditorConfigs: false)); } // when we run these tests, msbuild will find all .editorconfigs up to the root // of the drive. We can't control what might be outside the test directories // so we emulate that part of msbuild by finding any others and adding them to // the expected set of configs private string[] AppendExtraEditorConfigs(string[] expected, bool findEditorConfigs = true, bool findGlobalConfigs = true) { List<string> foundConfigs = new List<string>(); var dir = Directory.GetParent(ProjectDir.Path); while (dir is object && dir.Exists) { var editorConfigs = dir.GetFiles(".editorconfig"); if (findEditorConfigs && editorConfigs.Length == 1) { foundConfigs.Add(editorConfigs[0].FullName); } var globalConfigs = dir.GetFiles(".globalconfigs"); if (findGlobalConfigs && globalConfigs.Length == 1) { foundConfigs.Add(globalConfigs[0].FullName); } dir = dir.Parent; } foundConfigs.Reverse(); foundConfigs.AddRange(expected); return foundConfigs.ToArray(); } [ConditionalFact(typeof(DotNetSdkAvailable))] public void TestDiscoverEditorAndGlobalConfigFilesCanBeDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var globalConfigFile = ProjectDir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); var subdir = ProjectDir.CreateDirectory("subdir"); var globalConfigFile2 = subdir.CreateFile(".globalconfig").WriteAllText(@"is_global = true some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <DiscoverEditorConfigFiles>false</DiscoverEditorConfigFiles> <DiscoverGlobalAnalyzerConfigFiles>false</DiscoverGlobalAnalyzerConfigFiles> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: new[] { "" }); } [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestGlobalConfigsCanBeManuallyAdded() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); var globalConfigFile = ProjectDir.CreateFile("mycustom.config").WriteAllText(@"is_global = true some_prop = some_val"); VerifyValues( customProps: @" <PropertyGroup> <!-- Disable automatic global .editorconfig generation by the SDK --> <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile> </PropertyGroup> <ItemGroup> <GlobalAnalyzerConfigFiles Include=""mycustom.config"" /> </ItemGroup>", customTargets: null, targets: new[] { "CoreCompile" }, expressions: new[] { "@(EditorConfigFiles)" }, expectedResults: AppendExtraEditorConfigs(new[] { Path.Combine(ProjectDir.Path, ".editorconfig"), "mycustom.config" })); } } }