Skip to content

Commit 200634a

Browse files
authored
Merge pull request #484 from tonyhallett/support-testing-framework
add support
2 parents 2b90e07 + 3a5c9b6 commit 200634a

16 files changed

+460
-84
lines changed

FineCodeCoverage/FineCodeCoverage.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@
171171
<PackageReference Include="Microsoft.VisualStudio.Composition.Analyzers">
172172
<Version>16.9.20</Version>
173173
</PackageReference>
174+
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem">
175+
<Version>15.8.243</Version>
176+
</PackageReference>
174177
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="16.0.206" ExcludeAssets="runtime">
175178
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
176179
</PackageReference>

FineCodeCoverage2022/FineCodeCoverage2022.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@
170170
<PackageReference Include="Microsoft.VisualStudio.Composition.Analyzers">
171171
<Version>17.10.37</Version>
172172
</PackageReference>
173+
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem">
174+
<Version>17.9.380</Version>
175+
</PackageReference>
173176
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.10.40171" ExcludeAssets="runtime">
174177
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
175178
</PackageReference>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using FineCodeCoverage.Engine.Model;
2+
using NUnit.Framework;
3+
using System.IO;
4+
5+
namespace FineCodeCoverageTests
6+
{
7+
public class CoverageProject_Tests
8+
{
9+
private string tempProjectFilePath;
10+
private CoverageProject coverageProject;
11+
12+
[SetUp]
13+
public void SetUp()
14+
{
15+
coverageProject = new CoverageProject(null, null, null, null, null, false);
16+
tempProjectFilePath = Path.Combine(Path.GetTempPath(), "testproject.csproj");
17+
coverageProject.ProjectFile = tempProjectFilePath;
18+
}
19+
20+
[Test]
21+
public void Should_Be_An_Sdk_Project_When_Project_Element_Has_Sdk_Attribute()
22+
{
23+
Test(@"<Project Sdk=""My.Custom.Sdk/1.2.3""/>", true);
24+
}
25+
26+
[Test]
27+
public void Should_Be_An_Sdk_Project_When_Project_Element_Has_Child_Sdk_Element()
28+
{
29+
Test(@"<Project>
30+
<Sdk Name=""My.Custom.Sdk"" Version=""1.2.3"" />
31+
</Project>
32+
", true);
33+
}
34+
35+
[Test]
36+
public void Should_be_An_Sdk_Project_When_Project_Element_Has_Child_Import_With_Sdk_Attribute()
37+
{
38+
Test(@"<Project>
39+
<PropertyGroup>
40+
<MyProperty>Value</MyProperty>
41+
</PropertyGroup>
42+
<Import Project=""Sdk.props"" Sdk=""My.Custom.Sdk"" />
43+
</Project>
44+
", true);
45+
}
46+
47+
[Test]
48+
public void Should_Not_Be_An_Sdk_Project_When_Is_Not()
49+
{
50+
Test(@"<Project ToolsVersion=""15.0"" DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
51+
<Import Project=""..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.props"" Condition=""Exists('..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.props')"" />
52+
<Import Project=""..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props"" Condition=""Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')"" />
53+
<Import Project=""$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"" Condition=""Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"" />
54+
<PropertyGroup>
55+
<Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>
56+
<Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>
57+
<ProjectGuid>{F4B73E7F-F91D-4C95-A3CE-B8DA3A94BB90}</ProjectGuid>
58+
<OutputType>Library</OutputType>
59+
<AppDesignerFolder>Properties</AppDesignerFolder>
60+
<RootNamespace>NetFrameworkUnitTest</RootNamespace>
61+
<AssemblyName>NetFrameworkUnitTest</AssemblyName>
62+
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
63+
<FileAlignment>512</FileAlignment>
64+
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
65+
<VisualStudioVersion Condition=""'$(VisualStudioVersion)' == ''"">15.0</VisualStudioVersion>
66+
<VSToolsPath Condition=""'$(VSToolsPath)' == ''"">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
67+
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
68+
<IsCodedUITest>False</IsCodedUITest>
69+
<TestProjectType>UnitTest</TestProjectType>
70+
<NuGetPackageImportStamp>
71+
</NuGetPackageImportStamp>
72+
<RunSettingsFilePath>
73+
</RunSettingsFilePath>
74+
</PropertyGroup>
75+
<PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">
76+
<DebugSymbols>true</DebugSymbols>
77+
<DebugType>full</DebugType>
78+
<Optimize>false</Optimize>
79+
<OutputPath>bin\Debug\</OutputPath>
80+
<DefineConstants>DEBUG;TRACE</DefineConstants>
81+
<ErrorReport>prompt</ErrorReport>
82+
<WarningLevel>4</WarningLevel>
83+
</PropertyGroup>
84+
<PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "">
85+
<DebugType>pdbonly</DebugType>
86+
<Optimize>true</Optimize>
87+
<OutputPath>bin\Release\</OutputPath>
88+
<DefineConstants>TRACE</DefineConstants>
89+
<ErrorReport>prompt</ErrorReport>
90+
<WarningLevel>4</WarningLevel>
91+
</PropertyGroup>
92+
<ItemGroup>
93+
<Reference Include=""Microsoft.VisualStudio.CodeCoverage.Shim, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"">
94+
<HintPath>..\packages\Microsoft.CodeCoverage.17.12.0\lib\net462\Microsoft.VisualStudio.CodeCoverage.Shim.dll</HintPath>
95+
</Reference>
96+
<Reference Include=""Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"">
97+
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
98+
</Reference>
99+
<Reference Include=""Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"">
100+
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
101+
</Reference>
102+
<Reference Include=""System"" />
103+
<Reference Include=""System.Core"" />
104+
</ItemGroup>
105+
<ItemGroup>
106+
<Compile Include=""UnitTest1.cs"" />
107+
<Compile Include=""Properties\AssemblyInfo.cs"" />
108+
</ItemGroup>
109+
<ItemGroup>
110+
<None Include=""packages.config"" />
111+
</ItemGroup>
112+
<ItemGroup>
113+
<ProjectReference Include=""..\DemoOpenCover\DemoOpenCover.csproj"">
114+
<Project>{9ef61906-87e7-42ac-b977-058fc55f74d8}</Project>
115+
<Name>DemoOpenCover</Name>
116+
</ProjectReference>
117+
<ProjectReference Include=""..\Exclude\Exclude.csproj"">
118+
<Project>{fa82235f-9590-410b-9840-daa224abb17e}</Project>
119+
<Name>Exclude</Name>
120+
</ProjectReference>
121+
</ItemGroup>
122+
<Import Project=""$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets"" Condition=""Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')"" />
123+
<Import Project=""$(MSBuildToolsPath)\Microsoft.CSharp.targets"" />
124+
<Target Name=""EnsureNuGetPackageBuildImports"" BeforeTargets=""PrepareForBuild"">
125+
<PropertyGroup>
126+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
127+
</PropertyGroup>
128+
<Error Condition=""!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')"" Text=""$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))"" />
129+
<Error Condition=""!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')"" Text=""$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))"" />
130+
<Error Condition=""!Exists('..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.props')"" Text=""$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.props'))"" />
131+
<Error Condition=""!Exists('..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.targets')"" Text=""$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.targets'))"" />
132+
</Target>
133+
<Import Project=""..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets"" Condition=""Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')"" />
134+
<Import Project=""..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.targets"" Condition=""Exists('..\packages\Microsoft.CodeCoverage.17.12.0\build\netstandard2.0\Microsoft.CodeCoverage.targets')"" />
135+
</Project>", false);
136+
}
137+
138+
private void Test(string project, bool expectedIsSdkStyle)
139+
{
140+
var xmlDeclaration = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
141+
File.WriteAllText(tempProjectFilePath, $"{xmlDeclaration}{project}");
142+
Assert.That(coverageProject.IsDotNetSdkStyle(), Is.EqualTo(expectedIsSdkStyle));
143+
}
144+
145+
[TearDown]
146+
public void Delete_ProjectFile()
147+
{
148+
File.Delete(tempProjectFilePath);
149+
}
150+
}
151+
152+
}

FineCodeCoverageTests/FineCodeCoverageTests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
<ItemGroup>
6767
<Compile Include="CoberturaDeserializer_Tests.cs" />
6868
<Compile Include="CoberturaUtil_Tests.cs" />
69+
<Compile Include="CoverageProject_Tests.cs" />
6970
<Compile Include="CoverageToolOutput_Tests\AppOptionsCoverageToolOutputFolderSolutionProvider_Tests.cs" />
7071
<Compile Include="CoverageToolOutput_Tests\CoverageToolOutputFolderFromSolutionProvider_Tests.cs" />
7172
<Compile Include="CoverageToolOutput_Tests\CoverageToolOutputManager_Tests.cs" />

README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@ or download from [releases](https://github.com/FortuneN/FineCodeCoverage/release
1111

1212
## Prerequisites
1313

14-
For .Net - that the test adapters are nuget packages. For instance, the NUnit Test Adapter extension is not sufficient.
14+
For .Net
15+
16+
FCC supports the new [Microsoft.Testing.Platform]( https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-platform-intro).
17+
FCC does not support the associated testing platform server mode for when using microsoft as a coverage provider.
18+
You can disable this feature - "Options / Environment / Preview Features / Use testing platform server mode"
19+
but it is not necessary as FCC adds a global msbuild property, DisableTestingPlatformServerCapability true, that removes
20+
the project capability. ([see Microsoft.Testing.Platform.MSBuild.targets](https://github.com/microsoft/testfx/blob/d141931b99fad0617d8435ce321fca0c45c9eb94/src/Platform/Microsoft.Testing.Platform.MSBuild/buildMultiTargeting/Microsoft.Testing.Platform.MSBuild.targets#L10)).
21+
22+
When not using Microsoft.TestingPlatform you have added test adapters through nuget packages. For instance, the NUnit Test Adapter extension is not sufficient.
1523

1624
---
1725

SharedProject/Core/Model/CoverageProject.cs

+34-67
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ internal class CoverageProject : ICoverageProject
3232
private readonly string fccFolderName = "fine-code-coverage";
3333
private readonly string buildOutputFolderName = "build-output";
3434
private string buildOutputPath;
35+
private bool? isDotNetSdkStyle;
3536
private string BuildOutputPath
3637
{
3738
get
@@ -78,84 +79,50 @@ public CoverageProject(
7879
public string FCCOutputFolder => Path.Combine(ProjectOutputFolder, fccFolderName);
7980
public bool IsDotNetSdkStyle()
8081
{
81-
return ProjectFileXElement
82+
if (isDotNetSdkStyle.HasValue)
83+
{
84+
return isDotNetSdkStyle.Value;
85+
}
86+
87+
isDotNetSdkStyle = ProjectFileXElement
8288
.DescendantsAndSelf()
8389
.Where(x =>
8490
{
8591
//https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2019
92+
return IsRootProjectElementWithSdkAttribute(x) ||
93+
IsRootProjectElementSdkElementChild(x) ||
94+
IsRootImportElementWithSdkAttribute(x);
95+
})
96+
.Any();
8697

87-
/*
88-
<Project Sdk="My.Custom.Sdk">
89-
...
90-
</Project>
91-
<Project Sdk="My.Custom.Sdk/1.2.3">
92-
...
93-
</Project>
94-
*/
95-
if
96-
(
97-
x?.Name?.LocalName?.Equals("Project", StringComparison.OrdinalIgnoreCase) == true &&
98-
x?.Parent == null
99-
)
100-
{
101-
var sdkAttr = x?.Attributes()?.FirstOrDefault(attr => attr?.Name?.LocalName?.Equals("Sdk", StringComparison.OrdinalIgnoreCase) == true);
102-
103-
if (sdkAttr?.Value?.Trim()?.StartsWith("Microsoft.NET.Sdk", StringComparison.OrdinalIgnoreCase) == true)
104-
{
105-
return true;
106-
}
107-
}
98+
return isDotNetSdkStyle.Value;
10899

109-
/*
110-
<Project>
111-
<Sdk Name="My.Custom.Sdk" Version="1.2.3" />
112-
...
113-
</Project>
114-
*/
115-
if
116-
(
117-
x?.Name?.LocalName?.Equals("Sdk", StringComparison.OrdinalIgnoreCase) == true &&
118-
x?.Parent?.Name?.LocalName?.Equals("Project", StringComparison.OrdinalIgnoreCase) == true &&
119-
x?.Parent?.Parent == null
120-
)
121-
{
122-
var nameAttr = x?.Attributes()?.FirstOrDefault(attr => attr?.Name?.LocalName?.Equals("Name", StringComparison.OrdinalIgnoreCase) == true);
100+
bool HasSdkAttribute(XElement x)
101+
{
102+
return x?.Attributes()?.FirstOrDefault(attr => attr?.Name?.LocalName?.Equals("Sdk", StringComparison.OrdinalIgnoreCase) == true) != null;
103+
}
123104

124-
if (nameAttr?.Value?.Trim()?.StartsWith("Microsoft.NET.Sdk", StringComparison.OrdinalIgnoreCase) == true)
125-
{
126-
return true;
127-
}
128-
}
105+
bool IsRootProjectElementWithSdkAttribute(XElement x)
106+
{
107+
return x?.Name?.LocalName?.Equals("Project", StringComparison.OrdinalIgnoreCase) == true &&
108+
x?.Parent == null && HasSdkAttribute(x);
109+
}
129110

130-
/*
131-
<Project>
132-
<PropertyGroup>
133-
<MyProperty>Value</MyProperty>
134-
</PropertyGroup>
135-
<Import Project="Sdk.props" Sdk="My.Custom.Sdk" />
136-
...
137-
<Import Project="Sdk.targets" Sdk="My.Custom.Sdk" />
138-
</Project>
139-
*/
140-
if
141-
(
142-
x?.Name?.LocalName?.Equals("Import", StringComparison.OrdinalIgnoreCase) == true &&
111+
bool IsRootProjectElementSdkElementChild(XElement x)
112+
{
113+
return x?.Name?.LocalName?.Equals("Sdk", StringComparison.OrdinalIgnoreCase) == true &&
143114
x?.Parent?.Name?.LocalName?.Equals("Project", StringComparison.OrdinalIgnoreCase) == true &&
144-
x?.Parent?.Parent == null
145-
)
146-
{
147-
var sdkAttr = x?.Attributes()?.FirstOrDefault(attr => attr?.Name?.LocalName?.Equals("Sdk", StringComparison.OrdinalIgnoreCase) == true);
148-
149-
if (sdkAttr?.Value?.Trim()?.StartsWith("Microsoft.NET.Sdk", StringComparison.OrdinalIgnoreCase) == true)
150-
{
151-
return true;
152-
}
153-
}
115+
x?.Parent?.Parent == null;
116+
}
154117

155-
return false;
156-
})
157-
.Any();
118+
bool IsRootImportElementWithSdkAttribute(XElement x)
119+
{
120+
return x?.Name?.LocalName?.Equals("Import", StringComparison.OrdinalIgnoreCase) == true &&
121+
x?.Parent?.Name?.LocalName?.Equals("Project", StringComparison.OrdinalIgnoreCase) == true &&
122+
x?.Parent?.Parent == null && HasSdkAttribute(x);
123+
}
158124
}
125+
159126
public string TestDllFile { get; set; }
160127
public string ProjectOutputFolder => Path.GetDirectoryName(TestDllFile);
161128
public string FailureDescription { get; set; }

SharedProject/Core/MsTestPlatform/CodeCoverage/ProjectSaver.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace FineCodeCoverage.Core.MsTestPlatform.CodeCoverage
99
{
1010
interface IProjectSaver
1111
{
12-
void SaveProject(IVsHierarchy projectHierarchy);
12+
System.Threading.Tasks.Task SaveProjectAsync(IVsHierarchy projectHierarchy);
1313
}
1414

1515
[Export(typeof(IProjectSaver))]
@@ -26,9 +26,9 @@ IServiceProvider serviceProvider
2626
this.serviceProvider = serviceProvider;
2727
}
2828

29-
public void SaveProject(IVsHierarchy projectHierarchy)
29+
public async System.Threading.Tasks.Task SaveProjectAsync(IVsHierarchy projectHierarchy)
3030
{
31-
ThreadHelper.ThrowIfNotOnUIThread();
31+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
3232
var _solution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution));
3333
Assumes.Present(_solution);
3434
int hr = _solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, projectHierarchy, 0);

0 commit comments

Comments
 (0)