Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Contributions are highly welcome, however, except for very small changes, kindly

## Requirements

[.NET SDK 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
[.NET SDK 7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
[.NET SDK 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
STS version [.NET SDK 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) for development environment

LTS version [.NET SDK 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) for runtime environment

## Building the Project

Expand Down
13 changes: 6 additions & 7 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
</ItemGroup>
<PropertyGroup>
<MicrosoftBuildVersion>17.13.9</MicrosoftBuildVersion>
<MicrosoftCodeAnalysisVersion>4.12.0</MicrosoftCodeAnalysisVersion>
<MicrosoftCodeAnalysisVersion>4.13.0</MicrosoftCodeAnalysisVersion>
<!-- Test Platform, .NET Test SDK and Object Model -->
<MicrosoftNETTestSdkVersion>17.13.0</MicrosoftNETTestSdkVersion>
<NugetPackageVersion>6.13.2</NugetPackageVersion>
<XunitV3Version>2.0.0</XunitV3Version>
<XunitRunnerVisualstudioVersion>3.0.2</XunitRunnerVisualstudioVersion>
<XunitRunnerVisualstudioVersion>3.1.0</XunitRunnerVisualstudioVersion>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="DotNetConfig" Version="1.2.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildVersion)" />
<PackageVersion Include="Microsoft.Build.Framework" Version="$(MicrosoftBuildVersion)" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.7.8" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.9.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
Expand All @@ -39,7 +39,6 @@
vstest 17.8 version
NuGetFrameworksVersion is defined here https://github.com/microsoft/vstest/blob/9a0c41811637edf4afe0e265e08fdd1cb18109ed/eng/Versions.props#L94C1-L94C1
-->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NuGet.Frameworks" Version="$(NugetPackageVersion)" />
<PackageVersion Include="NuGet.Packaging" Version="$(NugetPackageVersion)" />
<PackageVersion Include="NuGet.Versioning" Version="$(NugetPackageVersion)" />
Expand All @@ -61,11 +60,11 @@
<PackageVersion Include="System.Memory" Version="4.6.0" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Reflection.Metadata" Version="8.0.1" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.0" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="6.0.5" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="8.0.1" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.0" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
</ItemGroup>
</Project>
6 changes: 3 additions & 3 deletions Documentation/VSTestIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ or
```text
dotnet publish
...
... -> C:\project\bin\Debug\net6.0\testdll.dll
... -> C:\project\bin\Debug\net6.0\publish\
... -> C:\project\bin\Debug\net8.0\testdll.dll
... -> C:\project\bin\Debug\net8.0\publish\
...
dotnet vstest C:\project\bin\Debug\net6.0\publish\testdll.dll --collect:"XPlat Code Coverage"
dotnet vstest C:\project\bin\Debug\net8.0\publish\testdll.dll --collect:"XPlat Code Coverage"
```

As you can see in case of `vstest` verb you **must** publish project before.
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Coverlet supports only SDK-style projects https://docs.microsoft.com/en-us/visua
```bash
dotnet add package coverlet.collector
```

N.B. You **MUST** add package only to test projects and if you create xunit test projects (`dotnet new xunit`) you'll find the reference already present in `csproj` file because Coverlet is the default coverage tool for every .NET Core and >= .NET 6 applications, you've only to update to last version if needed. Do not add `coverlet.collector` and `coverlet.msbuild` package in a test project.
> [!NOTE]
> You **MUST** add package only to test projects and if you create xunit test projects (`dotnet new xunit`) you will find the reference already present in `csproj` file because Coverlet is the default coverage tool for every .NET Core and >= *.NET 8* applications, you've only to update to last version if needed. Add `coverlet.collector` *OR* `coverlet.msbuild` package in a test project.

### Usage (coverlet.collector)

Expand All @@ -61,11 +61,11 @@ See [documentation](Documentation/VSTestIntegration.md) for advanced usage.

#### Requirements (coverlet.collector)

* _You need to be running .NET 6.0 SDK v6.0.316 or newer_
* _You need to reference version 17.5.0 and above of Microsoft.NET.Test.Sdk_
* _You need to be running .NET 8.0 SDK v8.0.112 or newer_
* _You need to reference version 17.12.0 and above of Microsoft.NET.Test.Sdk_

```xml
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
```

### MSBuild Integration (suffers of possible [known issue](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test))
Expand Down Expand Up @@ -120,7 +120,7 @@ See [documentation](Documentation/GlobalTool.md) for advanced usage.

.NET global tools rely on a .NET Core runtime installed on your machine https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#what-could-go-wrong

.NET Coverlet global tool requires _.NET Core 2.2 and above_
.NET Coverlet global tool requires _.NET 8.0 or above_

## How It Works

Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.407"
"version": "8.0.409"
}
}
25 changes: 17 additions & 8 deletions src/coverlet.core/Coverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Nodes;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Instrumentation;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Coverlet.Core
{
Expand Down Expand Up @@ -60,6 +60,14 @@ internal class Coverage

public string Identifier { get; }

readonly JsonSerializerOptions _options = new()
{
PropertyNameCaseInsensitive = true,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
IncludeFields = true,
WriteIndented = true
};

public Coverage(string moduleOrDirectory,
CoverageParameters parameters,
ILogger logger,
Expand Down Expand Up @@ -313,7 +321,7 @@ public CoverageResult GetCoverageResult()
{
_logger.LogInformation($"MergeWith: '{_parameters.MergeWith}'.");
string json = _fileSystem.ReadAllText(_parameters.MergeWith);
coverageResult.Merge(JsonConvert.DeserializeObject<Modules>(json));
coverageResult.Merge(JsonSerializer.Deserialize<Modules>(json, _options));
}
else
{
Expand Down Expand Up @@ -366,8 +374,8 @@ private void CalculateCoverage()
var documents = result.Documents.Values.ToList();
if (_parameters.UseSourceLink && result.SourceLink != null)
{
JToken jObject = JObject.Parse(result.SourceLink)["documents"];
Dictionary<string, string> sourceLinkDocuments = JsonConvert.DeserializeObject<Dictionary<string, string>>(jObject.ToString());
JsonNode jObject = JsonNode.Parse(result.SourceLink)["documents"];
Dictionary<string, string> sourceLinkDocuments = JsonSerializer.Deserialize<Dictionary<string, string>>(jObject.ToString());
foreach (Document document in documents)
{
document.Path = GetSourceLinkUrl(sourceLinkDocuments, document.Path);
Expand Down Expand Up @@ -480,9 +488,9 @@ internal string GetSourceLinkUrl(Dictionary<string, string> sourceLinkDocuments,
{
string key = sourceLinkDocument.Key;
if (Path.GetFileName(key) != "*") continue;

#pragma warning disable IDE0057
IReadOnlyList<SourceRootMapping> rootMapping = _sourceRootTranslator.ResolvePathRoot(key.Substring(0, key.Length - 1));

#pragma warning restore IDE0057
foreach (string keyMapping in rootMapping is null ? [key] : new List<string>(rootMapping.Select(m => m.OriginalPath)))
{
string directoryDocument = Path.GetDirectoryName(document);
Expand All @@ -494,8 +502,9 @@ internal string GetSourceLinkUrl(Dictionary<string, string> sourceLinkDocuments,
{
if (!directoryDocument.StartsWith(sourceLinkRoot + Path.DirectorySeparatorChar))
continue;

#pragma warning disable IDE0057
relativePath = directoryDocument.Substring(sourceLinkRoot.Length + 1);
#pragma warning restore IDE0057
}

if (relativePathOfBestMatch.Length == 0)
Expand Down
2 changes: 2 additions & 0 deletions src/coverlet.core/CoverageResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Coverlet.Core.Enums;
using Coverlet.Core.Instrumentation;

Expand All @@ -22,6 +23,7 @@ internal class Branches : List<BranchInfo> { }

internal class Method
{
[JsonConstructor]
internal Method()
{
Lines = [];
Expand Down
8 changes: 0 additions & 8 deletions src/coverlet.core/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,17 @@

namespace Coverlet.Core.Exceptions
{
[Serializable]
public class CoverletException : Exception
{
public CoverletException() { }
public CoverletException(string message) : base(message) { }
public CoverletException(string message, System.Exception inner) : base(message, inner) { }
protected CoverletException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}

[Serializable]
internal class CecilAssemblyResolutionException : CoverletException
{
public CecilAssemblyResolutionException() { }
public CecilAssemblyResolutionException(string message) : base(message) { }
public CecilAssemblyResolutionException(string message, System.Exception inner) : base(message, inner) { }
protected CecilAssemblyResolutionException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}
6 changes: 5 additions & 1 deletion src/coverlet.core/Helpers/InstrumentationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,17 +415,21 @@ private static string GetIncludeModuleKeysForValidFilters(char escapeSymbol, str
}

private static string CreateRegexExcludePattern(IEnumerable<string> filters, char escapeSymbol)
//only look for module filters here, types will be filtered out when instrumenting
//only look for module filters here, types will be filtered out when instrumenting
#pragma warning disable IDE0057 // Use range operator
=> CreateRegexPattern(filters, escapeSymbol, filter => filter.Substring(filter.IndexOf(']') + 1) == "*");
#pragma warning restore IDE0057 // Use range operator

private static string CreateRegexIncludePattern(IEnumerable<string> filters, char escapeSymbol) =>
CreateRegexPattern(filters, escapeSymbol);

private static string CreateRegexPattern(IEnumerable<string> filters, char escapeSymbol, Func<string, bool> filterPredicate = null)
{
IEnumerable<string> filteredFilters = filterPredicate != null ? filters.Where(filterPredicate) : filters;
#pragma warning disable IDE0057 // Use range operator
IEnumerable<string> regexPatterns = filteredFilters.Select(x =>
$"{escapeSymbol}{WildcardToRegex(x.Substring(1, x.IndexOf(']') - 1)).Trim('^', '$')}{escapeSymbol}");
#pragma warning restore IDE0057 // Use range operator
return string.Join("|", regexPatterns);
}

Expand Down
27 changes: 15 additions & 12 deletions src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Exceptions;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.DependencyModel.Resolution;
using Mono.Cecil;
using Newtonsoft.Json.Linq;
using NuGet.Versioning;

namespace Coverlet.Core.Instrumentation
Expand Down Expand Up @@ -296,29 +296,32 @@ public RuntimeConfigurationReader(string runtimeConfigFile)
{
string jsonString = File.ReadAllText(_runtimeConfigFile);

var jsonLoadSettings = new JsonLoadSettings()
var documentOptions = new JsonDocumentOptions
{
CommentHandling = CommentHandling.Ignore
CommentHandling = JsonCommentHandling.Skip
};

var configuration = JObject.Parse(jsonString, jsonLoadSettings);
using var configuration = JsonDocument.Parse(jsonString, documentOptions);

JToken rootElement = configuration.Root;
JToken runtimeOptionsElement = rootElement["runtimeOptions"];
JsonElement rootElement = configuration.RootElement;
JsonElement runtimeOptionsElement = rootElement.GetProperty("runtimeOptions");

if (runtimeOptionsElement?["framework"] != null)
if (runtimeOptionsElement.TryGetProperty("framework", out JsonElement frameworkElement))
{
return [(runtimeOptionsElement["framework"]["name"]?.Value<string>(), runtimeOptionsElement["framework"]["version"]?.Value<string>())];
return new List<(string, string)>
{
(runtimeOptionsElement.GetProperty("framework").GetProperty("name").GetString(), runtimeOptionsElement.GetProperty("framework").GetProperty("version").GetString())
};
}

if (runtimeOptionsElement?["frameworks"] != null)
if (runtimeOptionsElement.TryGetProperty("frameworks", out JsonElement frameworksElement))
{
return runtimeOptionsElement["frameworks"].Select(x => (x["name"]?.Value<string>(), x["version"]?.Value<string>())).ToList();
return frameworksElement.EnumerateArray().Select(x => (x.GetProperty("name").GetString(), x.GetProperty("version").GetString())).ToList();
}

if (runtimeOptionsElement?["includedFrameworks"] != null)
if (runtimeOptionsElement.TryGetProperty("includedFrameworks", out JsonElement runtimeoptionselement))
{
return runtimeOptionsElement["includedFrameworks"].Select(x => (x["name"]?.Value<string>(), x["version"]?.Value<string>())).ToList();
return runtimeoptionselement.EnumerateArray().Select(x => (x.GetProperty("name").GetString(), x.GetProperty("version").GetString())).ToList();
}

throw new InvalidOperationException($"Unable to read runtime configuration from {_runtimeConfigFile}.");
Expand Down
11 changes: 9 additions & 2 deletions src/coverlet.core/Reporters/JsonReporter.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Text.Encodings.Web;
using System.Text.Json;
using Coverlet.Core.Abstractions;
using Newtonsoft.Json;

namespace Coverlet.Core.Reporters
{
Expand All @@ -16,7 +17,13 @@ internal class JsonReporter : IReporter

public string Report(CoverageResult result, ISourceRootTranslator _)
{
return JsonConvert.SerializeObject(result.Modules, Formatting.Indented);
var options = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
IncludeFields = true,
WriteIndented = true,
};
return JsonSerializer.Serialize(result.Modules, options);
}
}
}
28 changes: 17 additions & 11 deletions src/coverlet.core/coverlet.core.csproj
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);IDE0057</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" VersionOverride="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" VersionOverride="6.0.2" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" VersionOverride="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" VersionOverride="6.0.2" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Mono.Cecil" />
<PackageReference Include="NuGet.Versioning" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="System.Text.Json" VersionOverride="6.0.11" />
<PackageReference Include="System.Text.Json" />
<PackageReference Include="System.Threading.Tasks.Extensions" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<PackageReference Include="System.Reflection.Metadata" />
<PackageReference Include="System.Collections.Immutable" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Reflection.Metadata" VersionOverride="$(SystemReflectionMetadataVersion)" />
<PackageReference Include="System.Collections.Immutable" VersionOverride="$(SystemCollectionsImmutableVersion)" />
<PackageReference Include="System.Buffers" />
<PackageReference Include="System.Memory" />
<PackageReference Include="System.Threading.Tasks.Extensions" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/coverlet.msbuild.tasks/coverlet.msbuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PropertyGroup>
<_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion)</_CoverletSdkNETCoreSdkVersion>
<_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0])</_CoverletSdkNETCoreSdkVersion>
<_CoverletSdkMinVersionWithDependencyTarget>6.0.100</_CoverletSdkMinVersionWithDependencyTarget>
<_CoverletSdkMinVersionWithDependencyTarget>8.0.100</_CoverletSdkMinVersionWithDependencyTarget>
<_CoverletSourceRootTargetName>CoverletGetPathMap</_CoverletSourceRootTargetName>
<_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' &gt;= '0' ">InitializeSourceRootMappedPaths</_CoverletSourceRootTargetName>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
</ItemGroup>

</Project>
Loading