From 06ce08abb28e417f17fc9d91b897da5ebb59ce45 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 08:59:47 +0200 Subject: [PATCH 01/16] Update .NET versions and project configurations - Set `NetCurrent` to `net9.0` and `NetMinimum` to `net8.0` in `Directory.Build.props`. - Updated SDK version in `global.json` to `9.0.203`. - Changed target frameworks in `coverlet.collector.csproj`, `coverlet.console.csproj`, `coverlet.core.csproj`, and `coverlet.msbuild.tasks.csproj` to support multiple frameworks. - Modified `CoverletToolsPath` in `Directory.Build.targets` to include `netstandard2.0`. - Updated coverage file naming in `Msbuild.cs` to reflect the build target framework. --- Directory.Build.props | 7 +- Directory.Packages.props | 25 ++---- README.md | 12 +-- eng/build.yml | 18 ++-- eng/publish-coverlet-result-files.yml | 10 ++- global.json | 2 +- .../coverlet.collector.csproj | 5 +- src/coverlet.console/coverlet.console.csproj | 3 +- src/coverlet.core/Coverage.cs | 25 ++++-- src/coverlet.core/CoverageResult.cs | 2 + src/coverlet.core/Exceptions.cs | 8 -- .../Helpers/InstrumentationHelper.cs | 6 +- .../Instrumentation/CecilAssemblyResolver.cs | 27 +++--- src/coverlet.core/Reporters/JsonReporter.cs | 11 ++- src/coverlet.core/coverlet.core.csproj | 23 +++--- .../coverlet.msbuild.props | 4 + .../coverlet.msbuild.props | 6 +- .../coverlet.msbuild.targets | 2 +- .../coverlet.msbuild.tasks.csproj | 6 +- test/Directory.Build.targets | 4 +- .../coverlet.core.coverage.tests.csproj | 3 +- .../Coverage/CoverageTests.cs | 76 ++++++++++------- .../coverlet.core.tests.csproj | 3 +- ...verlet.integration.determisticbuild.csproj | 3 +- .../nuget.config | 2 +- .../DeterministicBuild.cs | 82 +++++++++++-------- test/coverlet.integration.tests/DotnetTool.cs | 2 +- .../coverlet.integration.tests.csproj | 6 +- .../coverlet.msbuild.tasks.tests.csproj | 9 +- test/coverlet.tests.utils/TestUtils.cs | 4 +- 30 files changed, 231 insertions(+), 165 deletions(-) create mode 100644 src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props diff --git a/Directory.Build.props b/Directory.Build.props index 0b0e187d0..195bbb0a8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,6 +2,9 @@ $(MSBuildThisFileDirectory) + net9.0 + net8.0 + net472 Debug @@ -39,12 +42,12 @@ - $(RepoRoot)artifacts/testresults/$(Configuration.ToLowerInvariant()) + $(RepoRoot)artifacts/reports/$(Configuration.ToLowerInvariant()) @(VSTestLogger) - $(RepoRoot)artifacts\testresults\$(Configuration.ToLowerInvariant()) + $(RepoRoot)artifacts\reports\$(Configuration.ToLowerInvariant()) @(VSTestLogger) diff --git a/Directory.Packages.props b/Directory.Packages.props index eba94e254..7b7ef4f56 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,20 +8,23 @@ - 17.13.9 - 4.12.0 + 17.11.4 + 4.13.0 17.13.0 6.13.2 2.0.0 3.0.2 + 6.0.0 + 4.5.5 + 8.0.0 - + @@ -30,16 +33,6 @@ - - - - - @@ -58,14 +51,14 @@ - + - + - + diff --git a/README.md b/README.md index cea37fcfc..39aa23b69 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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 - + ``` ### 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)) @@ -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 diff --git a/eng/build.yml b/eng/build.yml index 570bd0f2c..c93583f28 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -4,10 +4,15 @@ steps: version: 6.0.428 displayName: Install .NET Core SDK 6.0.428 +- task: UseDotNet@2 + inputs: + version: 8.0.114 + displayName: Install .NET Core SDK 8.0.114 + - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 8.0.113 + displayName: Install .NET Core SDK 9.0.202 # create artifact/package folder - pwsh: | @@ -25,11 +30,12 @@ steps: displayName: Pack - script: | - dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory)/artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.tests.trx" --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)" --diagnostic-output-fileprefix "coverlet.core.tests" - dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory)/artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)" --diagnostic-output-fileprefix "coverlet.core.coverage.tests" - dotnet test test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.binlog --results-directory:"$(Build.SourcesDirectory)\artifacts\Reports" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.xunit.extensions]*%2c[coverlet.tests.projectsample]*%2c[testgen_]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)\artifacts\log\$(buildConfiguration)\coverlet.msbuild.test.diag.log;tracelevel=verbose" - dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)/coverlet.collector.test.diag.log;tracelevel=verbose" - dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.integration.binlog -- --results-directory "$(Build.SourcesDirectory)/artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.integration.tests.trx" --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)" --diagnostic-output-fileprefix "coverlet.integration.tests" + dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.test.diag.$(BuildConfiguration.log;tracelevel=verbose" + dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.coverage.test.diag.$(BuildConfiguration.log;tracelevel=verbose" + dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.test.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net9.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net9.0.$(buildConfiguration).log;tracelevel=verbose" displayName: Run unit tests with coverage env: MSBUILDDISABLENODEREUSE: 1 diff --git a/eng/publish-coverlet-result-files.yml b/eng/publish-coverlet-result-files.yml index c8addb84c..c30a8fcde 100644 --- a/eng/publish-coverlet-result-files.yml +++ b/eng/publish-coverlet-result-files.yml @@ -34,7 +34,15 @@ steps: condition: always() inputs: SourceFolder: '$(Build.SourcesDirectory)' - Contents: '**/*.binlog' + Contents: '*.binlog' + TargetFolder: '$(Build.SourcesDirectory)/artifacts/TestLogs' + +- task: CopyFiles@2 + displayName: Copy DeterministicBuild binlog files + condition: always() + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: 'test\coverlet.integration.determisticbuild\*.binlog' TargetFolder: '$(Build.SourcesDirectory)/artifacts/TestLogs' - task: PublishPipelineArtifact@1 diff --git a/global.json b/global.json index 6dfc6666e..a42b43018 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.407" + "version": "9.0.203" } } diff --git a/src/coverlet.collector/coverlet.collector.csproj b/src/coverlet.collector/coverlet.collector.csproj index 7630bb845..5a2b55fb2 100644 --- a/src/coverlet.collector/coverlet.collector.csproj +++ b/src/coverlet.collector/coverlet.collector.csproj @@ -1,6 +1,6 @@ - netstandard2.0 + $(NetMinimum);netstandard2.0 coverlet.collector true true @@ -40,8 +40,11 @@ + + + diff --git a/src/coverlet.console/coverlet.console.csproj b/src/coverlet.console/coverlet.console.csproj index 2a7181b18..88a695d6a 100644 --- a/src/coverlet.console/coverlet.console.csproj +++ b/src/coverlet.console/coverlet.console.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + $(NetMinimum) coverlet true coverlet.console @@ -25,6 +25,7 @@ + diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index 3cc80c4c8..918d8aedf 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -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 { @@ -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, @@ -313,7 +321,7 @@ public CoverageResult GetCoverageResult() { _logger.LogInformation($"MergeWith: '{_parameters.MergeWith}'."); string json = _fileSystem.ReadAllText(_parameters.MergeWith); - coverageResult.Merge(JsonConvert.DeserializeObject(json)); + coverageResult.Merge(JsonSerializer.Deserialize(json, _options)); } else { @@ -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 sourceLinkDocuments = JsonConvert.DeserializeObject>(jObject.ToString()); + JsonNode jObject = JsonNode.Parse(result.SourceLink)["documents"]; + Dictionary sourceLinkDocuments = JsonSerializer.Deserialize>(jObject.ToString()); foreach (Document document in documents) { document.Path = GetSourceLinkUrl(sourceLinkDocuments, document.Path); @@ -480,9 +488,9 @@ internal string GetSourceLinkUrl(Dictionary sourceLinkDocuments, { string key = sourceLinkDocument.Key; if (Path.GetFileName(key) != "*") continue; - +#pragma warning disable IDE0057 IReadOnlyList rootMapping = _sourceRootTranslator.ResolvePathRoot(key.Substring(0, key.Length - 1)); - +#pragma warning restore IDE0057 foreach (string keyMapping in rootMapping is null ? [key] : new List(rootMapping.Select(m => m.OriginalPath))) { string directoryDocument = Path.GetDirectoryName(document); @@ -494,8 +502,9 @@ internal string GetSourceLinkUrl(Dictionary 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) diff --git a/src/coverlet.core/CoverageResult.cs b/src/coverlet.core/CoverageResult.cs index 7b002053c..c3a92ee29 100644 --- a/src/coverlet.core/CoverageResult.cs +++ b/src/coverlet.core/CoverageResult.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using Coverlet.Core.Enums; using Coverlet.Core.Instrumentation; @@ -22,6 +23,7 @@ internal class Branches : List { } internal class Method { + [JsonConstructor] internal Method() { Lines = []; diff --git a/src/coverlet.core/Exceptions.cs b/src/coverlet.core/Exceptions.cs index d65b22096..365df85f3 100644 --- a/src/coverlet.core/Exceptions.cs +++ b/src/coverlet.core/Exceptions.cs @@ -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) { } } } diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs index 0b1b3439c..e6e3f0702 100644 --- a/src/coverlet.core/Helpers/InstrumentationHelper.cs +++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs @@ -415,8 +415,10 @@ private static string GetIncludeModuleKeysForValidFilters(char escapeSymbol, str } private static string CreateRegexExcludePattern(IEnumerable 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 filters, char escapeSymbol) => CreateRegexPattern(filters, escapeSymbol); @@ -424,8 +426,10 @@ private static string CreateRegexIncludePattern(IEnumerable filters, cha private static string CreateRegexPattern(IEnumerable filters, char escapeSymbol, Func filterPredicate = null) { IEnumerable filteredFilters = filterPredicate != null ? filters.Where(filterPredicate) : filters; +#pragma warning disable IDE0057 // Use range operator IEnumerable 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); } diff --git a/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs b/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs index 649b6c369..ecef745e2 100644 --- a/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs +++ b/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs @@ -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 @@ -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(), runtimeOptionsElement["framework"]["version"]?.Value())]; + 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(), x["version"]?.Value())).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(), x["version"]?.Value())).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}."); diff --git a/src/coverlet.core/Reporters/JsonReporter.cs b/src/coverlet.core/Reporters/JsonReporter.cs index e684e8c8a..62be3373a 100644 --- a/src/coverlet.core/Reporters/JsonReporter.cs +++ b/src/coverlet.core/Reporters/JsonReporter.cs @@ -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 { @@ -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); } } } diff --git a/src/coverlet.core/coverlet.core.csproj b/src/coverlet.core/coverlet.core.csproj index f3e16e3f1..7bac1e92d 100644 --- a/src/coverlet.core/coverlet.core.csproj +++ b/src/coverlet.core/coverlet.core.csproj @@ -1,24 +1,25 @@ - + Library - netstandard2.0 + $(NetMinimum);netstandard2.0 false + $(NoWarn);IDE0057 - - - - + + - - - + + + + + - - + + diff --git a/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props b/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props new file mode 100644 index 000000000..ba0c4ed38 --- /dev/null +++ b/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.props b/src/coverlet.msbuild.tasks/coverlet.msbuild.props index 94f3d0d9d..53ec786b4 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.props +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.props @@ -19,9 +19,11 @@ - $(MSBuildThisFileDirectory)..\tasks\netstandard2.0\ + $(MSBuildThisFileDirectory)..\tasks\net8.0\ + $(MSBuildThisFileDirectory)..\tasks\netstandard2.0\ - $(MSBuildThisFileDirectory)../tasks/netstandard2.0/ + $(MSBuildThisFileDirectory)../tasks/net8.0/ + $(MSBuildThisFileDirectory)../tasks/netstandard2.0/ diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets index e8bbfac20..0defe0138 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets @@ -6,7 +6,7 @@ <_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion) <_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0]) - <_CoverletSdkMinVersionWithDependencyTarget>6.0.100 + <_CoverletSdkMinVersionWithDependencyTarget>8.0.100 <_CoverletSourceRootTargetName>CoverletGetPathMap <_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' >= '0' ">InitializeSourceRootMappedPaths diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index c04e823b0..57104ff72 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -2,7 +2,7 @@ Library - netstandard2.0 + netstandard2.0;$(NetMinimum) coverlet.msbuild.tasks true $(TargetsForTfmSpecificContentInPackage);PackBuildOutputs @@ -40,6 +40,7 @@ + @@ -51,6 +52,9 @@ Always + + Always + Always diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 3cd6c793b..8b989e8bd 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -14,8 +14,8 @@ This is required when the coverlet.msbuild imports are made in their src directory (so that msbuild eval works even before they are built) so that they can still find the tooling that will be built by the build. --> - - $(RepoRoot)artifacts\bin\coverlet.msbuild.tasks\$(Configuration.ToLower())\ + $(RepoRoot)artifacts\bin\coverlet.msbuild.tasks\$(Configuration.ToLowerInvariant())_netstandard2.0\ + diff --git a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj index 43b19b7ad..71a6e7595 100644 --- a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj +++ b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj @@ -3,9 +3,8 @@ net8.0 - true Exe - true + true false true $(NoWarn);CS8002 diff --git a/test/coverlet.core.tests/Coverage/CoverageTests.cs b/test/coverlet.core.tests/Coverage/CoverageTests.cs index 86a306269..f99dbb4e6 100644 --- a/test/coverlet.core.tests/Coverage/CoverageTests.cs +++ b/test/coverlet.core.tests/Coverage/CoverageTests.cs @@ -1,16 +1,17 @@ -// Copyright (c) Toni Solarin-Sodara +// Copyright (c) Toni Solarin-Sodara // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections; using System.Collections.Generic; using System.IO; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; using Coverlet.Core.Instrumentation; using Coverlet.Core.Symbols; using Moq; -using Newtonsoft.Json; using Xunit; namespace Coverlet.Core.Tests @@ -18,6 +19,16 @@ namespace Coverlet.Core.Tests public partial class CoverageTests { private readonly Mock _mockLogger = new(); + readonly JsonSerializerOptions _options = new() + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + IncludeFields = true, + WriteIndented = true, + Converters = + { + new BranchDictionaryConverterFactory() + } + }; [Fact] public void TestCoverage() @@ -90,7 +101,7 @@ public void TestCoverageWithTestAssembly() new SourceRootTranslator(module, _mockLogger.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); coverage.PrepareModules(); - string result = JsonConvert.SerializeObject(coverage.GetCoverageResult(), Formatting.Indented, new BranchDictionaryConverter()); + string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options); Assert.Contains("coverlet.core.tests.dll", result); @@ -129,7 +140,7 @@ public void TestCoverageMergeWithParameter() var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); coverage.PrepareModules(); - string result = JsonConvert.SerializeObject(coverage.GetCoverageResult(), Formatting.Indented, new BranchDictionaryConverter()); + string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options); Assert.Contains("DeepThought.cs", result); @@ -170,7 +181,7 @@ public void TestCoverageMergeWithWrongParameter() var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); coverage.PrepareModules(); - JsonConvert.SerializeObject(coverage.GetCoverageResult()); + string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options); _mockLogger.Verify(l => l.LogInformation(It.Is(v => v.Equals("MergeWith: file 'FileDoesNotExist.json' does not exist.")), It.IsAny()), Times.Once); @@ -220,36 +231,43 @@ public void GetSourceLinkUrl_ReturnsOriginalDocument_WhenNoMatch() } } - public class BranchDictionaryConverter : JsonConverter + public class BranchDictionaryConverterFactory : JsonConverterFactory { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override bool CanConvert(Type typeToConvert) { - Type type = value.GetType(); - var keys = (IEnumerable)type.GetProperty("Keys")?.GetValue(value, null); - var values = (IEnumerable)type.GetProperty("Values")?.GetValue(value, null); - IEnumerator valueEnumerator = values.GetEnumerator(); - - writer.WriteStartArray(); - foreach (object key in keys) - { - valueEnumerator.MoveNext(); - - writer.WriteStartArray(); - serializer.Serialize(writer, key); - serializer.Serialize(writer, valueEnumerator.Current); - writer.WriteEndArray(); - } - writer.WriteEndArray(); + return typeof(Dictionary).IsAssignableFrom(typeToConvert); } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { - throw new NotImplementedException(); + Type[] genericArgs = typeToConvert.GetGenericArguments(); + Type keyType = genericArgs[0]; + Type valueType = genericArgs[1]; + + JsonConverter converter = (JsonConverter)Activator.CreateInstance( + typeof(BranchDictionaryConverter<,>).MakeGenericType(new Type[] { keyType, valueType })); + + return converter; } + } +} - public override bool CanConvert(Type objectType) +public class BranchDictionaryConverter : JsonConverter> +{ + public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, Dictionary value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + foreach (KeyValuePair pair in value) { - return typeof(Dictionary).IsAssignableFrom(objectType); + writer.WritePropertyName(pair.Key.ToString()); + JsonSerializer.Serialize(writer, pair.Value, options); } + + writer.WriteEndObject(); } } diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index ff6c28869..eeac7e12a 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -1,11 +1,10 @@ - + net8.0 Exe true - true true false $(NoWarn);CS8002 diff --git a/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj b/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj index 38d1c8820..28e6552aa 100644 --- a/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj +++ b/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj @@ -3,7 +3,7 @@ - net6.0 + net9.0;net8.0 false coverletsample.integration.determisticbuild NU1604;NU1701 @@ -29,6 +29,5 @@ all runtime; build; native; contentfiles; analyzers - diff --git a/test/coverlet.integration.template/nuget.config b/test/coverlet.integration.template/nuget.config index fbcef1011..765346e53 100644 --- a/test/coverlet.integration.template/nuget.config +++ b/test/coverlet.integration.template/nuget.config @@ -2,6 +2,6 @@ - + diff --git a/test/coverlet.integration.tests/DeterministicBuild.cs b/test/coverlet.integration.tests/DeterministicBuild.cs index 9c8a181db..343dd69be 100644 --- a/test/coverlet.integration.tests/DeterministicBuild.cs +++ b/test/coverlet.integration.tests/DeterministicBuild.cs @@ -16,21 +16,23 @@ namespace Coverlet.Integration.Tests public class DeterministicBuild : BaseTest, IDisposable { private static readonly string s_projectName = "coverlet.integration.determisticbuild"; - //private readonly string _buildTargetFramework; - private string? _testProjectTfm; + private readonly string _buildTargetFramework; + private string[] _testProjectTfms = []; private readonly string _testProjectPath = TestUtils.GetTestProjectPath(s_projectName); private readonly string _testBinaryPath = TestUtils.GetTestBinaryPath(s_projectName); - private readonly string _testResultsPath = TestUtils.GetTestResultsPath(s_projectName); + private readonly string _testResultsPath = TestUtils.GetTestResultsPath(); private const string PropsFileName = "DeterministicTest.props"; private readonly string _buildConfiguration; private readonly ITestOutputHelper _output; private readonly Type _type; private readonly FieldInfo? _testMember; + private readonly string _artifactsPivot; public DeterministicBuild(ITestOutputHelper output) { _buildConfiguration = TestUtils.GetAssemblyBuildConfiguration().ToString(); - //_buildTargetFramework = TestUtils.GetAssemblyTargetFramework(); + _buildTargetFramework = TestUtils.GetAssemblyTargetFramework(); + _artifactsPivot = _buildConfiguration + "_" + _buildTargetFramework; _output = output; _type = output.GetType(); _testMember = _type.GetField("test", BindingFlags.Instance | BindingFlags.NonPublic); @@ -38,25 +40,34 @@ public DeterministicBuild(ITestOutputHelper output) private void CreateDeterministicTestPropsFile() { - var deterministicTestProps = new XDocument(); + string propsFile = Path.Combine(_testProjectPath, PropsFileName); + File.Delete(propsFile); + + XDocument deterministicTestProps = new(); deterministicTestProps.Add( new XElement("Project", new XElement("PropertyGroup", new XElement("coverletMsbuildVersion", GetPackageVersion("*msbuild*.nupkg")), new XElement("coverletCollectorsVersion", GetPackageVersion("*collector*.nupkg"))))); - _testProjectTfm = XElement.Load(Path.Combine(_testProjectPath, "coverlet.integration.determisticbuild.csproj"))!. - Descendants("PropertyGroup")!.Single().Element("TargetFramework")!.Value; + _testProjectTfms = XElement.Load(Path.Combine(_testProjectPath, "coverlet.integration.determisticbuild.csproj"))! + .Descendants("PropertyGroup")! + .Single() + .Element("TargetFrameworks")! + .Value + .Split(';'); + + Assert.Contains(_buildTargetFramework, _testProjectTfms); - deterministicTestProps.Save(Path.Combine(_testProjectPath, PropsFileName)); + deterministicTestProps.Save(Path.Combine(propsFile)); } - private protected void AssertCoverage(string standardOutput = "", bool checkDeterministicReport = true) + private protected void AssertCoverage(string standardOutput = "", string reportName = "", bool checkDeterministicReport = true) { if (_buildConfiguration == "Debug") { bool coverageChecked = false; string reportFilePath = ""; - foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.json", SearchOption.AllDirectories)) + foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput, reportName), reportName, SearchOption.AllDirectories)) { Classes? document = JsonConvert.DeserializeObject(File.ReadAllText(coverageFile))?.Document("DeepThought.cs"); if (document != null) @@ -74,8 +85,9 @@ private protected void AssertCoverage(string standardOutput = "", bool checkDete if (checkDeterministicReport) { + string newName = reportName.Replace("json", "cobertura.xml"); // Verify deterministic report - foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.cobertura.xml", SearchOption.AllDirectories)) + foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput, newName), newName, SearchOption.AllDirectories)) { Assert.Contains("/_/test/coverlet.integration.determisticbuild/DeepThought.cs", File.ReadAllText(coverageFile)); File.Delete(coverageFile); @@ -91,7 +103,7 @@ public void Msbuild() string logFilename = $"{TestContext.Current.TestClass?.TestClassName}.{TestContext.Current.TestMethod?.MethodName}.binlog"; CreateDeterministicTestPropsFile(); - DotnetCli($"build -c {_buildConfiguration} -bl:build.{logFilename} /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); + DotnetCli($"build -c {_buildConfiguration} -f {_buildTargetFramework} -bl:build.{logFilename} /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); if (!string.IsNullOrEmpty(buildError)) { _output.WriteLine(buildError); @@ -101,13 +113,12 @@ public void Msbuild() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _buildConfiguration.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.False(string.IsNullOrEmpty(File.ReadAllText(sourceRootMappingFilePath))); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string testResultFile = Path.Join(testResultPath, "coverage.json"); - string cmdArgument = $"test -c {_buildConfiguration} --no-build /p:CollectCoverage=true /p:CoverletOutput=\"{testResultFile}\" /p:DeterministicReport=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:DeterministicReport=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -121,8 +132,9 @@ public void Msbuild() Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); Assert.Contains("| coverletsample.integration.determisticbuild | 100% | 100% | 100% |", standardOutput); - Assert.True(File.Exists(testResultFile)); - AssertCoverage(standardOutput); + string testResultFile = Path.Join(_testProjectPath, $"coverage.{_buildTargetFramework}.json"); + Assert.True(File.Exists(testResultFile), $"File '{testResultFile}' does not exist"); + AssertCoverage(standardOutput, $"coverage.{_buildTargetFramework}.json"); CleanupBuildOutput(); } @@ -134,7 +146,7 @@ public void Msbuild_SourceLink() string logFilename = $"{TestContext.Current.TestClass?.TestClassName}.{TestContext.Current.TestMethod?.MethodName}.binlog"; CreateDeterministicTestPropsFile(); - DotnetCli($"build -c {_buildConfiguration} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); + DotnetCli($"build -c {_buildConfiguration} -f {_buildTargetFramework} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); if (!string.IsNullOrEmpty(buildError)) { _output.WriteLine(buildError); @@ -144,14 +156,13 @@ public void Msbuild_SourceLink() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _buildConfiguration.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.False(string.IsNullOrEmpty(File.ReadAllText(sourceRootMappingFilePath))); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string testResultFile = Path.Join(testResultPath, "coverage.json"); - string cmdArgument = $"test -c {_buildConfiguration} --no-build /p:CollectCoverage=true /p:CoverletOutput=\"{testResultFile}\" /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:UseSourceLink=true /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:UseSourceLink=true /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -165,9 +176,10 @@ public void Msbuild_SourceLink() Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); Assert.Contains("| coverletsample.integration.determisticbuild | 100% | 100% | 100% |", standardOutput); - Assert.True(File.Exists(testResultFile)); + string testResultFile = Path.Join(_testProjectPath, $"coverage.{_buildTargetFramework}.json"); + Assert.True(File.Exists(testResultFile), $"File '{testResultFile}' does not exist"); Assert.Contains("raw.githubusercontent.com", File.ReadAllText(testResultFile)); - AssertCoverage(standardOutput, checkDeterministicReport: false); + AssertCoverage(standardOutput, $"coverage.{_buildTargetFramework}.json", checkDeterministicReport: false); CleanupBuildOutput(); } @@ -183,7 +195,7 @@ public void Collectors() DeleteLogFiles(testLogFilesPath); DeleteCoverageFiles(testResultPath); - DotnetCli($"build -c {_buildConfiguration} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); + DotnetCli($"build -c {_buildConfiguration} -f {_buildTargetFramework} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); if (!string.IsNullOrEmpty(buildError)) { _output.WriteLine(buildError); @@ -193,14 +205,14 @@ public void Collectors() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _buildConfiguration.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath)); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", deterministicReport: true); - string cmdArgument = $"test -c {_buildConfiguration} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -213,7 +225,7 @@ public void Collectors() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); - AssertCoverage(standardOutput); + AssertCoverage(standardOutput, "coverage.json"); // delete irrelevant generated files DeleteTestIntermediateFiles(testResultPath); @@ -238,7 +250,7 @@ public void Collectors_SourceLink() DeleteLogFiles(testLogFilesPath); DeleteCoverageFiles(testResultPath); - DotnetCli($"build -c {_buildConfiguration} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); + DotnetCli($"build -c {_buildConfiguration} -f {_buildTargetFramework} -bl:build.{logFilename} --verbosity normal /p:DeterministicSourcePaths=true", out string buildOutput, out string buildError, _testProjectPath); if (!string.IsNullOrEmpty(buildError)) { _output.WriteLine(buildError); @@ -248,14 +260,14 @@ public void Collectors_SourceLink() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _buildConfiguration.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath)); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true); - string cmdArgument = $"test -c {_buildConfiguration} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -268,7 +280,7 @@ public void Collectors_SourceLink() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); - AssertCoverage(standardOutput, checkDeterministicReport: false); + AssertCoverage(standardOutput, "coverage.json", checkDeterministicReport: false); // delete irrelevant generated files DeleteTestIntermediateFiles(testResultPath); @@ -365,14 +377,14 @@ private static void DeleteCoverageFiles(string directory) } } - private string GetReportPath(string standardOutput) + private string GetReportPath(string standardOutput, string reportFileName = "") { string reportPath = ""; - if (standardOutput.Contains("coverage.json")) + if (standardOutput.Contains(reportFileName)) { - reportPath = standardOutput.Split('\n').FirstOrDefault(line => line.Contains("coverage.json"))!.TrimStart(); + reportPath = standardOutput.Split('\n').FirstOrDefault(line => line.Contains(reportFileName))!.TrimStart(); reportPath = reportPath[reportPath.IndexOf(Directory.GetDirectoryRoot(_testProjectPath))..]; - reportPath = reportPath[..reportPath.IndexOf("coverage.json")]; + reportPath = reportPath[..reportPath.IndexOf(reportFileName)]; } return reportPath; } diff --git a/test/coverlet.integration.tests/DotnetTool.cs b/test/coverlet.integration.tests/DotnetTool.cs index 91e989f02..c37e1156d 100644 --- a/test/coverlet.integration.tests/DotnetTool.cs +++ b/test/coverlet.integration.tests/DotnetTool.cs @@ -1,4 +1,4 @@ -// Copyright (c) Toni Solarin-Sodara +// Copyright (c) Toni Solarin-Sodara // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.IO; diff --git a/test/coverlet.integration.tests/coverlet.integration.tests.csproj b/test/coverlet.integration.tests/coverlet.integration.tests.csproj index 4c8cc9c50..5a1e8f02e 100644 --- a/test/coverlet.integration.tests/coverlet.integration.tests.csproj +++ b/test/coverlet.integration.tests/coverlet.integration.tests.csproj @@ -1,9 +1,8 @@ - net8.0 + $(NetCurrent);$(NetMinimum) Exe true - true false enable false @@ -17,13 +16,12 @@ + all runtime; build; native; contentfiles; analyzers - - diff --git a/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj b/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj index f363d52ac..1e77b344b 100644 --- a/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj +++ b/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj @@ -1,11 +1,9 @@  - net8.0 - - enable true false @@ -20,7 +18,7 @@ - + @@ -38,6 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + diff --git a/test/coverlet.tests.utils/TestUtils.cs b/test/coverlet.tests.utils/TestUtils.cs index f24f13399..3d2dde584 100644 --- a/test/coverlet.tests.utils/TestUtils.cs +++ b/test/coverlet.tests.utils/TestUtils.cs @@ -57,9 +57,9 @@ public static string GetPackagePath(string buildConfiguration) return Path.Join(Path.GetFullPath(Path.Join(AppContext.BaseDirectory, s_rel3Parents)), "package", buildConfiguration); } - public static string GetTestResultsPath(string directoryName) + public static string GetTestResultsPath() { - return Path.Join(Path.GetFullPath(Path.Join(AppContext.BaseDirectory, s_rel3Parents)), "testresults", directoryName); + return Path.Join(Path.GetFullPath(Path.Join(AppContext.BaseDirectory, s_rel3Parents)), "reports"); } } From 128ea2a8f541b0317c3585fd53fc635c19eec3ba Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 09:15:19 +0200 Subject: [PATCH 02/16] update build.yml .NET SDK versions --- eng/azure-pipelines-nightly.yml | 6 +++--- eng/build.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/azure-pipelines-nightly.yml b/eng/azure-pipelines-nightly.yml index ab78bae71..e2e8904da 100644 --- a/eng/azure-pipelines-nightly.yml +++ b/eng/azure-pipelines-nightly.yml @@ -4,13 +4,13 @@ pool: steps: - task: UseDotNet@2 inputs: - version: 6.0.428 - displayName: Install .NET Core SDK 6.0.428 + version: 8.0.408 + displayName: Install .NET Core SDK 8.0.408 - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 8.0.113 + displayName: Install .NET Core SDK 9.0.203 - task: NuGetAuthenticate@1 displayName: Authenticate with NuGet feeds diff --git a/eng/build.yml b/eng/build.yml index c93583f28..803edabdd 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -6,13 +6,13 @@ steps: - task: UseDotNet@2 inputs: - version: 8.0.114 - displayName: Install .NET Core SDK 8.0.114 + version: 8.0.408 + displayName: Install .NET Core SDK 8.0.408 - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 9.0.202 + displayName: Install .NET Core SDK 9.0.203 # create artifact/package folder - pwsh: | From d42ac59a8f8b7f47792051d47c70a4cfdd2f071d Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 09:48:43 +0200 Subject: [PATCH 03/16] check net9.0 instead of net6.0 --- test/coverlet.integration.tests/Msbuild.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/coverlet.integration.tests/Msbuild.cs b/test/coverlet.integration.tests/Msbuild.cs index abb784d10..a61776449 100644 --- a/test/coverlet.integration.tests/Msbuild.cs +++ b/test/coverlet.integration.tests/Msbuild.cs @@ -152,7 +152,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameWithDoubleExtension() public void Test_MultipleTargetFrameworkReport_NoCoverletOutput() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!); if (!string.IsNullOrEmpty(standardError)) @@ -178,7 +178,7 @@ public void Test_MultipleTargetFrameworkReport_NoCoverletOutput() public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); int result = DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true /p:CoverletOutput=\"{clonedTemplateProject.ProjectRootPath}\"\\", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!); if (!string.IsNullOrEmpty(standardError)) @@ -206,7 +206,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder() public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWithoutExtension() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true /p:CoverletOutput=\"{clonedTemplateProject.ProjectRootPath}\"\\file", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!); if (!string.IsNullOrEmpty(standardError)) @@ -232,7 +232,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWithExtension_SpecifyFramework() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); Assert.True(clonedTemplateProject.IsMultipleTargetFramework()); string[] frameworks = clonedTemplateProject.GetTargetFrameworks(); @@ -269,7 +269,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWithExtension() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true /p:CoverletOutput=\"{clonedTemplateProject.ProjectRootPath}\"\\file.ext", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!); if (!string.IsNullOrEmpty(standardError)) @@ -295,7 +295,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWithDoubleExtension() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0", "net8.0" }; + string[] targetFrameworks = new string[] { "net9.0", "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true /p:CoverletOutput=\"{clonedTemplateProject.ProjectRootPath}\"\\file.ext1.ext2", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!); if (!string.IsNullOrEmpty(standardError)) From 1f4696f0203c3707ae7805a4fe7d039492e4e3c9 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 10:28:03 +0200 Subject: [PATCH 04/16] fix log file names --- eng/build.yml | 8 ++++---- eng/publish-coverlet-result-files.yml | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/eng/build.yml b/eng/build.yml index 803edabdd..7acab5499 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -30,10 +30,10 @@ steps: displayName: Pack - script: | - dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.test.diag.$(BuildConfiguration.log;tracelevel=verbose" - dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.coverage.test.diag.$(BuildConfiguration.log;tracelevel=verbose" - dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" - dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.test.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.tests.diag.$(BuildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.coverage.tests.diag.$(BuildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.msbuild.tasks.tests.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net9.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net9.0.$(buildConfiguration).log;tracelevel=verbose" displayName: Run unit tests with coverage diff --git a/eng/publish-coverlet-result-files.yml b/eng/publish-coverlet-result-files.yml index c30a8fcde..de280a2d3 100644 --- a/eng/publish-coverlet-result-files.yml +++ b/eng/publish-coverlet-result-files.yml @@ -15,6 +15,11 @@ steps: **/log.txt **/log.datacollector.*.txt **/log.host.*.txt + **/coverlet.integration.tests.diag*.log + **/coverlet.collector.tests.diag*.log + **/coverlet.msbuild.tasks.tests.diag*.log + **/coverlet.core.coverage.tests.diag*.log + **/coverlet.core.tests.diag*.log TargetFolder: '$(Build.SourcesDirectory)/artifacts/TestLogs' - task: CopyFiles@2 From 5fef652a5fa3aa3a398ee8f1773fd95cfdf95892 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 11:05:06 +0200 Subject: [PATCH 05/16] update targetFrameworks and documentation --- Documentation/VSTestIntegration.md | 14 +++++++------- test/coverlet.integration.tests/Msbuild.cs | 2 +- ...coverlet.tests.projectsample.aspmvcrazor.csproj | 2 +- test/coverlet.tests.utils/TestUtils.cs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/VSTestIntegration.md b/Documentation/VSTestIntegration.md index a2c4140e1..c0f5f355f 100644 --- a/Documentation/VSTestIntegration.md +++ b/Documentation/VSTestIntegration.md @@ -2,12 +2,12 @@ **Supported runtime versions**: -Since version `6.0.0` +Since version `8.0.0` -* .NET Core >= 6.0 +* .NET Core >= 8.0 * .NET Framework >= 4.7.2 -As explained in quick start section, to use collectors you need to run *SDK v6.0.100* (LTS) or newer and your project file must reference `coverlet.collector` and a minimum version of `Microsoft.NET.Test.Sdk`. +As explained in quick start section, to use collectors you need to run *SDK v8.0.100* (LTS) or newer and your project file must reference `coverlet.collector` and a minimum version of `Microsoft.NET.Test.Sdk`. A sample project file looks like: @@ -20,7 +20,7 @@ A sample project file looks like: - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -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. diff --git a/test/coverlet.integration.tests/Msbuild.cs b/test/coverlet.integration.tests/Msbuild.cs index a61776449..86acea9fc 100644 --- a/test/coverlet.integration.tests/Msbuild.cs +++ b/test/coverlet.integration.tests/Msbuild.cs @@ -109,7 +109,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameExtension() public void TestMsbuild_CoverletOutput_Folder_FileNameExtension_SpecifyFramework() { using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string[] targetFrameworks = new string[] { "net6.0" }; + string[] targetFrameworks = new string[] { "net8.0" }; UpdateProjectTargetFramework(clonedTemplateProject, targetFrameworks); Assert.False(clonedTemplateProject.IsMultipleTargetFramework()); string framework = clonedTemplateProject.GetTargetFrameworks().Single(); diff --git a/test/coverlet.tests.projectsample.aspmvcrazor/coverlet.tests.projectsample.aspmvcrazor.csproj b/test/coverlet.tests.projectsample.aspmvcrazor/coverlet.tests.projectsample.aspmvcrazor.csproj index 6e46d7306..cf1079a1b 100644 --- a/test/coverlet.tests.projectsample.aspmvcrazor/coverlet.tests.projectsample.aspmvcrazor.csproj +++ b/test/coverlet.tests.projectsample.aspmvcrazor/coverlet.tests.projectsample.aspmvcrazor.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 enable false false diff --git a/test/coverlet.tests.utils/TestUtils.cs b/test/coverlet.tests.utils/TestUtils.cs index 3d2dde584..8a89196ac 100644 --- a/test/coverlet.tests.utils/TestUtils.cs +++ b/test/coverlet.tests.utils/TestUtils.cs @@ -33,8 +33,8 @@ public static BuildConfiguration GetAssemblyBuildConfiguration() public static string GetAssemblyTargetFramework() { -#if NET6_0 - return "net6.0"; +#if NET9_0 + return "net9.0"; #endif #if NET8_0 return "net8.0"; From ddbff07c32fad3f5625d9b84dbcd0d28a2addd95 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 11:29:57 +0200 Subject: [PATCH 06/16] enable TestingPlatformDotnetTestSupport --- .../coverlet.core.coverage.tests.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj index 71a6e7595..5eabe6aea 100644 --- a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj +++ b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj @@ -1,10 +1,11 @@ - + net8.0 Exe true + true false true $(NoWarn);CS8002 From 144eef55f05061085ccfd3c3be41519d7beb8265 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Apr 2025 11:35:21 +0200 Subject: [PATCH 07/16] remove net6.0 from build script --- eng/build.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/eng/build.yml b/eng/build.yml index 7acab5499..cb43adf9c 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -1,9 +1,4 @@ steps: -- task: UseDotNet@2 - inputs: - version: 6.0.428 - displayName: Install .NET Core SDK 6.0.428 - - task: UseDotNet@2 inputs: version: 8.0.408 From abebdce166bcd16b7d699ffdfd6d0a1012dd5352 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 17 Apr 2025 16:21:48 +0200 Subject: [PATCH 08/16] update scripts --- eng/build.sh | 11 ++++++----- eng/build.yml | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/eng/build.sh b/eng/build.sh index 35b5b75b7..3c66d52be 100644 --- a/eng/build.sh +++ b/eng/build.sh @@ -22,12 +22,13 @@ dotnet pack -c release dotnet build-server shutdown # Run tests with code coverage -dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c debug --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.tests.trx" --diagnostic --diagnostic-output-directory "artifacts/log/debug" --diagnostic-output-fileprefix "coverlet.core.tests" +dotnet test test/coverlet.collector.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" --results-directory:"./artifacts/reports" --diag:"artifacts/log/debug/coverlet.collector.test.log;tracelevel=verbose" dotnet build-server shutdown -dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c debug --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic --diagnostic-output-directory "artifacts/log/debug" --diagnostic-output-fileprefix "coverlet.core.coverage.tests" +dotnet test test/coverlet.core.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.core.tests.log dotnet build-server shutdown -dotnet test test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj -c debug --no-build -bl:test.msbuild.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory:"artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.msbuild.tasks.tests.trx" --diagnostic --diagnostic-output-directory "artifacts/log/debug" --diagnostic-output-fileprefix "coverlet.msbuild.tasks.tests" +dotnet test test/coverlet.core.coverage.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" -- --results-directory "$(pwd)/artifacts/reports" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(pwd)/artifacts/log/debug" dotnet build-server shutdown -dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c debug --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"artifacts/log/debug/coverlet.collector.test.diag.log;tracelevel=verbose" +dotnet test test/coverlet.msbuild.tasks.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.msbuild.tasks.tests.log dotnet build-server shutdown -dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c debug --no-build -bl:test.integration.binlog -- --results-directory "artifacts/Reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.integration.tests.trx" --diagnostic --diagnostic-output-directory "artifacts/log/debug" --diagnostic-output-fileprefix "coverlet.integration.tests" +dotnet test test/coverlet.integration.tests -f net8.0 --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.integration.tests.net8.log +dotnet test test/coverlet.integration.tests -f net9.0 --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.integration.tests.net9.log diff --git a/eng/build.yml b/eng/build.yml index cb43adf9c..2cfef6fd8 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -25,10 +25,10 @@ steps: displayName: Pack - script: | - dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.tests.diag.$(BuildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.coverage.tests.diag.$(BuildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.msbuild.tasks.tests.diag.$(buildConfiguration).log;tracelevel=verbose" - dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net9.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net9.0.$(buildConfiguration).log;tracelevel=verbose" displayName: Run unit tests with coverage From 7e7bb0aee909102d2d3d4c3e47129d258cf5c23f Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 17 Apr 2025 16:45:49 +0200 Subject: [PATCH 09/16] fix parameters --- eng/build.sh | 2 +- eng/build.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/build.sh b/eng/build.sh index 3c66d52be..a1e1891fa 100644 --- a/eng/build.sh +++ b/eng/build.sh @@ -26,7 +26,7 @@ dotnet test test/coverlet.collector.tests /p:CollectCoverage=true /p:CoverletOut dotnet build-server shutdown dotnet test test/coverlet.core.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.core.tests.log dotnet build-server shutdown -dotnet test test/coverlet.core.coverage.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" -- --results-directory "$(pwd)/artifacts/reports" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(pwd)/artifacts/log/debug" +dotnet test test/coverlet.core.coverage.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" -- --results-directory "$(pwd)/artifacts/reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(pwd)/artifacts/log/debug" dotnet build-server shutdown dotnet test test/coverlet.msbuild.tasks.tests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*" --results-directory:"./artifacts/reports" --verbosity detailed --diag ./artifacts/log/debug/coverlet.msbuild.tasks.tests.log dotnet build-server shutdown diff --git a/eng/build.yml b/eng/build.yml index 2cfef6fd8..47d74c6a8 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -26,8 +26,8 @@ steps: - script: | dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" - dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" - dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.coverage.tests.diag.$(BuildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.tests.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.msbuild.tasks.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net9.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net9.0.$(buildConfiguration).log;tracelevel=verbose" From 2d016ac416d8b8ccdbb481067fd3a7ccd6116cd1 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 5 Jun 2025 16:12:53 +0200 Subject: [PATCH 10/16] add method GetSourceRootMappingFilePath --- global.json | 2 +- .../DeterministicBuild.cs | 75 ++++++++++++++----- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/global.json b/global.json index a42b43018..09b6cadd0 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.203" + "version": "9.0.300" } } diff --git a/test/coverlet.integration.tests/DeterministicBuild.cs b/test/coverlet.integration.tests/DeterministicBuild.cs index 343dd69be..d9f4e326d 100644 --- a/test/coverlet.integration.tests/DeterministicBuild.cs +++ b/test/coverlet.integration.tests/DeterministicBuild.cs @@ -16,6 +16,7 @@ namespace Coverlet.Integration.Tests public class DeterministicBuild : BaseTest, IDisposable { private static readonly string s_projectName = "coverlet.integration.determisticbuild"; + private static readonly string s_sutName = "coverletsample.integration.determisticbuild"; private readonly string _buildTargetFramework; private string[] _testProjectTfms = []; private readonly string _testProjectPath = TestUtils.GetTestProjectPath(s_projectName); @@ -67,7 +68,7 @@ private protected void AssertCoverage(string standardOutput = "", string reportN { bool coverageChecked = false; string reportFilePath = ""; - foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput, reportName), reportName, SearchOption.AllDirectories)) + foreach (string coverageFile in Directory.GetFiles(GetReportDirectory(standardOutput, reportName), reportName, SearchOption.AllDirectories)) { Classes? document = JsonConvert.DeserializeObject(File.ReadAllText(coverageFile))?.Document("DeepThought.cs"); if (document != null) @@ -87,9 +88,9 @@ private protected void AssertCoverage(string standardOutput = "", string reportN { string newName = reportName.Replace("json", "cobertura.xml"); // Verify deterministic report - foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput, newName), newName, SearchOption.AllDirectories)) + foreach (string coverageFile in Directory.GetFiles(GetReportDirectory(standardOutput, newName), newName, SearchOption.AllDirectories)) { - Assert.Contains("/_/test/coverlet.integration.determisticbuild/DeepThought.cs", File.ReadAllText(coverageFile)); + Assert.Contains($"/_/test/{s_projectName}/DeepThought.cs", File.ReadAllText(coverageFile)); File.Delete(coverageFile); } } @@ -113,12 +114,12 @@ public void Msbuild() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = GetSourceRootMappingFilePath(buildOutput, $"CoverletSourceRootsMapping_{s_sutName}"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.False(string.IsNullOrEmpty(File.ReadAllText(sourceRootMappingFilePath))); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:DeterministicReport=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:DeterministicReport=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:Include=\"[{s_sutName}]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -131,10 +132,11 @@ public void Msbuild() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); - Assert.Contains("| coverletsample.integration.determisticbuild | 100% | 100% | 100% |", standardOutput); - string testResultFile = Path.Join(_testProjectPath, $"coverage.{_buildTargetFramework}.json"); + Assert.Contains($"| {s_sutName} | 100% | 100% | 100% |", standardOutput); + string filename = $"coverage.{_buildTargetFramework}.json"; + string testResultFile = GetReportDirectory(standardOutput, filename) + filename; Assert.True(File.Exists(testResultFile), $"File '{testResultFile}' does not exist"); - AssertCoverage(standardOutput, $"coverage.{_buildTargetFramework}.json"); + AssertCoverage(standardOutput, filename); CleanupBuildOutput(); } @@ -156,13 +158,13 @@ public void Msbuild_SourceLink() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = GetSourceRootMappingFilePath(buildOutput, $"CoverletSourceRootsMapping_{s_sutName}"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.False(string.IsNullOrEmpty(File.ReadAllText(sourceRootMappingFilePath))); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:UseSourceLink=true /p:Include=\"[coverletsample.integration.determisticbuild]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; + string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=\"cobertura%2cjson\" /p:UseSourceLink=true /p:Include=\"[{s_sutName}]*DeepThought\" /p:IncludeTestAssembly=true --results-directory:{testResultPath}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); if (!string.IsNullOrEmpty(standardError)) @@ -175,11 +177,12 @@ public void Msbuild_SourceLink() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput); - Assert.Contains("| coverletsample.integration.determisticbuild | 100% | 100% | 100% |", standardOutput); - string testResultFile = Path.Join(_testProjectPath, $"coverage.{_buildTargetFramework}.json"); + Assert.Contains($"| {s_sutName} | 100% | 100% | 100% |", standardOutput); + string filename = $"coverage.{_buildTargetFramework}.json"; + string testResultFile = GetReportDirectory(standardOutput, filename) + filename; Assert.True(File.Exists(testResultFile), $"File '{testResultFile}' does not exist"); Assert.Contains("raw.githubusercontent.com", File.ReadAllText(testResultFile)); - AssertCoverage(standardOutput, $"coverage.{_buildTargetFramework}.json", checkDeterministicReport: false); + AssertCoverage(standardOutput, filename, checkDeterministicReport: false); CleanupBuildOutput(); } @@ -205,13 +208,13 @@ public void Collectors() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = GetSourceRootMappingFilePath(buildOutput, $"CoverletSourceRootsMapping_{s_sutName}"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath)); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", deterministicReport: true); + string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, $"[{s_sutName}]*DeepThought", deterministicReport: true); string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); @@ -260,13 +263,13 @@ public void Collectors_SourceLink() _output.WriteLine(buildOutput); } Assert.Contains("Build succeeded.", buildOutput); - string sourceRootMappingFilePath = Path.Combine(_testBinaryPath, _artifactsPivot.ToLowerInvariant(), "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild"); + string sourceRootMappingFilePath = GetSourceRootMappingFilePath(buildOutput, $"CoverletSourceRootsMapping_{s_sutName}"); Assert.True(File.Exists(sourceRootMappingFilePath), $"File not found: {sourceRootMappingFilePath}"); Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath)); Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath)); - string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true); + string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, $"[{s_sutName}]*DeepThought", sourceLink: true); string cmdArgument = $"test -c {_buildConfiguration} -f {_buildTargetFramework} --no-build --collect:\"XPlat Code Coverage\" --results-directory:\"{testResultPath}\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(testLogFilesPath, "log.txt")}"; _output.WriteLine($"Command: dotnet {cmdArgument}"); int result = DotnetCli(cmdArgument, out string standardOutput, out string standardError, _testProjectPath); @@ -377,7 +380,7 @@ private static void DeleteCoverageFiles(string directory) } } - private string GetReportPath(string standardOutput, string reportFileName = "") + private string GetReportDirectory(string standardOutput, string reportFileName = "") { string reportPath = ""; if (standardOutput.Contains(reportFileName)) @@ -388,6 +391,42 @@ private string GetReportPath(string standardOutput, string reportFileName = "") } return reportPath; } + + private static string GetSourceRootMappingFilePath(string buildOutput, string pattern) + { + // search file in path using pattern and return full path + // this will also handle filenames with prefix like ".msCoverletSourceRootsMapping_coverletsample.integration.determisticbuild" or "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild" + // today both files exist + string sourceRootMappingFilePath = ""; + if (buildOutput.Contains($"{s_sutName}.dll")) + { + string[] lines = buildOutput.Split('\n').Where(line => line.Contains(" -> ")).ToArray(); + if (lines.Length == 0) + { + throw new InvalidOperationException("No lines found in build output containing ' -> '."); + } + else + { + string? directory = Path.GetDirectoryName(lines.FirstOrDefault(static line => line.Contains($"{s_sutName}.dll"))?.TrimStart()); + if (directory == null) + { + throw new InvalidOperationException($"Directory is null. {s_sutName}.dll not found."); + } + // actual directory value "coverlet.integration.determisticbuild -> C:\GitHub\coverlet\artifacts\bin\coverlet.integration.determisticbuild\debug + // remove everything before '->' + directory = directory[(directory.IndexOf("->") + 2)..].Trim(); + if (Directory.Exists(directory)) + { + string[] files = Directory.GetFiles(directory, $"{pattern}*", SearchOption.AllDirectories); + if (files.Length > 0) + { + sourceRootMappingFilePath = files[0]; + } + } + } + } + return sourceRootMappingFilePath; + } public void Dispose() { File.Delete(Path.Combine(_testProjectPath, PropsFileName)); From 31034d1437eb1847b8bfe9b1e90a41a49cc3315b Mon Sep 17 00:00:00 2001 From: Bert Date: Mon, 9 Jun 2025 10:16:47 +0200 Subject: [PATCH 11/16] delete wrong file --- .../buildMultiTargeting/coverlet.msbuild.props | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props diff --git a/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props b/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props deleted file mode 100644 index ba0c4ed38..000000000 --- a/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From afda748b51eeee686b57fe596174ada33d6e55c9 Mon Sep 17 00:00:00 2001 From: Bert Date: Mon, 9 Jun 2025 10:29:01 +0200 Subject: [PATCH 12/16] improve nuget packaging --- .../build/coverlet.collector.targets | 2 +- .../coverlet.collector.csproj | 17 +++++++------- .../build/coverlet.msbuild.props | 3 +++ .../build/coverlet.msbuild.targets | 3 +++ .../coverlet.msbuild.props | 0 .../coverlet.msbuild.targets | 0 .../coverlet.msbuild.tasks.csproj | 23 +++++++++++-------- .../coverlet.collector.tests.csproj | 4 ++-- .../coverlet.core.coverage.tests.csproj | 4 ++-- .../coverlet.core.performancetest.csproj | 4 ++-- .../coverlet.core.tests.csproj | 4 ++-- .../coverlet.msbuild.tasks.tests.csproj | 4 ++-- 12 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 src/coverlet.msbuild.tasks/build/coverlet.msbuild.props create mode 100644 src/coverlet.msbuild.tasks/build/coverlet.msbuild.targets rename src/coverlet.msbuild.tasks/{ => buildMultiTargeting}/coverlet.msbuild.props (100%) rename src/coverlet.msbuild.tasks/{ => buildMultiTargeting}/coverlet.msbuild.targets (100%) diff --git a/src/coverlet.collector/build/coverlet.collector.targets b/src/coverlet.collector/build/coverlet.collector.targets index 12cf946c8..c0cf57d6d 100644 --- a/src/coverlet.collector/build/coverlet.collector.targets +++ b/src/coverlet.collector/build/coverlet.collector.targets @@ -27,7 +27,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and <_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion) <_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0]) - <_CoverletSdkMinVersionWithDependencyTarget>6.0.100 + <_CoverletSdkMinVersionWithDependencyTarget>8.0.100 <_CoverletSourceRootTargetName>CoverletGetPathMap <_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' >= '0' ">InitializeSourceRootMappedPaths diff --git a/src/coverlet.collector/coverlet.collector.csproj b/src/coverlet.collector/coverlet.collector.csproj index 5a2b55fb2..6ce0c0722 100644 --- a/src/coverlet.collector/coverlet.collector.csproj +++ b/src/coverlet.collector/coverlet.collector.csproj @@ -44,7 +44,6 @@ - @@ -56,20 +55,20 @@ + + - - Always - + + build/$(TargetFramework) + - + - - - - + + diff --git a/src/coverlet.msbuild.tasks/build/coverlet.msbuild.props b/src/coverlet.msbuild.tasks/build/coverlet.msbuild.props new file mode 100644 index 000000000..22c499a45 --- /dev/null +++ b/src/coverlet.msbuild.tasks/build/coverlet.msbuild.props @@ -0,0 +1,3 @@ + + + diff --git a/src/coverlet.msbuild.tasks/build/coverlet.msbuild.targets b/src/coverlet.msbuild.tasks/build/coverlet.msbuild.targets new file mode 100644 index 000000000..6ffa91bd5 --- /dev/null +++ b/src/coverlet.msbuild.tasks/build/coverlet.msbuild.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.props b/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props similarity index 100% rename from src/coverlet.msbuild.tasks/coverlet.msbuild.props rename to src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.props diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets b/src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.targets similarity index 100% rename from src/coverlet.msbuild.tasks/coverlet.msbuild.targets rename to src/coverlet.msbuild.tasks/buildMultiTargeting/coverlet.msbuild.targets diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index 57104ff72..120d94639 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -49,21 +49,26 @@ - - Always - - - Always - - - Always - true + + + + + buildMultiTargeting + + + buildTransitive/$(TargetFramework) + + + build/$(TargetFramework) + + + diff --git a/test/coverlet.collector.tests/coverlet.collector.tests.csproj b/test/coverlet.collector.tests/coverlet.collector.tests.csproj index 5e7fd0793..c92dfdbe2 100644 --- a/test/coverlet.collector.tests/coverlet.collector.tests.csproj +++ b/test/coverlet.collector.tests/coverlet.collector.tests.csproj @@ -1,5 +1,5 @@ - + net8.0 @@ -23,5 +23,5 @@ - + diff --git a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj index 5eabe6aea..e95a53ece 100644 --- a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj +++ b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj @@ -1,5 +1,5 @@  - + net8.0 @@ -37,5 +37,5 @@ - + diff --git a/test/coverlet.core.performancetest/coverlet.core.performancetest.csproj b/test/coverlet.core.performancetest/coverlet.core.performancetest.csproj index 20135c047..67bca27ce 100644 --- a/test/coverlet.core.performancetest/coverlet.core.performancetest.csproj +++ b/test/coverlet.core.performancetest/coverlet.core.performancetest.csproj @@ -1,5 +1,5 @@  - + net8.0 @@ -20,5 +20,5 @@ - + diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index eeac7e12a..4c5ac27cd 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -1,5 +1,5 @@  - + net8.0 @@ -74,5 +74,5 @@ - + diff --git a/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj b/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj index 1e77b344b..27baabf29 100644 --- a/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj +++ b/test/coverlet.msbuild.tasks.tests/coverlet.msbuild.tasks.tests.csproj @@ -1,5 +1,5 @@  - + $(NetMinimum) Exe @@ -56,5 +56,5 @@ - + From c7e25b2476db98748ffa75402457b75c0248dde9 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 13 Jun 2025 09:36:34 +0200 Subject: [PATCH 13/16] Update SDK and Directory.Packages.props --- .config/dotnet-tools.json | 4 +-- .gitignore | 1 + CONTRIBUTING.md | 6 ++-- Directory.Build.props | 31 ------------------- Directory.Packages.props | 16 +++++----- eng/build.yml | 8 ++--- global.json | 2 +- .../Instrumentation/CecilAssemblyResolver.cs | 5 ++- src/coverlet.core/coverlet.core.csproj | 11 ++++--- .../coverlet.msbuild.tasks.csproj | 2 +- ...rlet.core.tests.samples.netstandard.csproj | 2 +- test/coverlet.integration.tests/Collectors.cs | 14 ++++----- .../DeterministicBuild.cs | 8 +++++ test/coverlet.tests.utils/TestUtils.cs | 7 +++-- 14 files changed, 50 insertions(+), 67 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 1903d864e..4c03ce6b6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,11 +3,11 @@ "isRoot": true, "tools": { "dotnet-reportgenerator-globaltool": { - "version": "5.4.3", + "version": "5.4.7", "commands": [ "reportgenerator" ], "rollForward": false } } -} \ No newline at end of file +} diff --git a/.gitignore b/.gitignore index 514880624..2179436d8 100644 --- a/.gitignore +++ b/.gitignore @@ -318,3 +318,4 @@ FolderProfile.pubxml /NuGet.config nuget.config *.dmp +Playground*/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ffe337455..f0616b11f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/Directory.Build.props b/Directory.Build.props index 195bbb0a8..70c56b8f6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,35 +51,4 @@ @(VSTestLogger) - - - - - 15.9.20 - 1.6.0 - 1.5.0 - - - - diff --git a/Directory.Packages.props b/Directory.Packages.props index 7b7ef4f56..e4b2c0807 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,20 +4,16 @@ true - - 17.11.4 + 17.13.26 4.13.0 + 6.14.0 17.13.0 - 6.13.2 2.0.0 - 3.0.2 - 6.0.0 - 4.5.5 - 8.0.0 + 3.1.0 @@ -47,15 +43,17 @@ - + + - + + diff --git a/eng/build.yml b/eng/build.yml index 47d74c6a8..301842a84 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -1,13 +1,13 @@ steps: - task: UseDotNet@2 inputs: - version: 8.0.408 - displayName: Install .NET Core SDK 8.0.408 + version: 8.0.411 + displayName: Install .NET Core SDK 8.0.411 - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 9.0.203 + displayName: Install .NET Core SDK 9.0.301 # create artifact/package folder - pwsh: | @@ -25,10 +25,10 @@ steps: displayName: Pack - script: | - dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.core.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic-verbosity debug --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.msbuild.tasks.tests.diag.$(buildConfiguration).log;tracelevel=verbose" + dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(buildConfiguration).log;tracelevel=verbose" dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net9.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net9.0.$(buildConfiguration).log;tracelevel=verbose" displayName: Run unit tests with coverage diff --git a/global.json b/global.json index 09b6cadd0..1e11058e8 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.300" + "version": "9.0.301" } } diff --git a/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs b/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs index ecef745e2..e4f0e19bd 100644 --- a/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs +++ b/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs @@ -304,7 +304,10 @@ public RuntimeConfigurationReader(string runtimeConfigFile) using var configuration = JsonDocument.Parse(jsonString, documentOptions); JsonElement rootElement = configuration.RootElement; - JsonElement runtimeOptionsElement = rootElement.GetProperty("runtimeOptions"); + if (!rootElement.TryGetProperty("runtimeOptions", out JsonElement runtimeOptionsElement)) + { + throw new InvalidOperationException($"The 'runtimeOptions' property is missing in the runtime configuration file {_runtimeConfigFile}."); + } if (runtimeOptionsElement.TryGetProperty("framework", out JsonElement frameworkElement)) { diff --git a/src/coverlet.core/coverlet.core.csproj b/src/coverlet.core/coverlet.core.csproj index 7bac1e92d..a974bd7df 100644 --- a/src/coverlet.core/coverlet.core.csproj +++ b/src/coverlet.core/coverlet.core.csproj @@ -8,18 +8,19 @@ - + + - - - - + + + + diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index 120d94639..cadaac8e3 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -41,7 +41,7 @@ - + diff --git a/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj b/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj index 36bc43a36..a7ce141f5 100644 --- a/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj +++ b/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/coverlet.integration.tests/Collectors.cs b/test/coverlet.integration.tests/Collectors.cs index a19e814e1..fb5a935cc 100644 --- a/test/coverlet.integration.tests/Collectors.cs +++ b/test/coverlet.integration.tests/Collectors.cs @@ -9,11 +9,11 @@ namespace Coverlet.Integration.Tests { - public class TestSDK_17_8_0 : Collectors + public class TestSDK_17_13_0 : Collectors { - public TestSDK_17_8_0() + public TestSDK_17_13_0() { - TestSDKVersion = "17.8.0"; + TestSDKVersion = "17.13.0"; } private protected override void AssertCollectorsInjection(ClonedTemplateProject clonedTemplateProject) @@ -27,11 +27,11 @@ private protected override void AssertCollectorsInjection(ClonedTemplateProject } } - public class TestSDK_17_6_0 : Collectors + public class TestSDK_17_12_0 : Collectors { - public TestSDK_17_6_0() + public TestSDK_17_12_0() { - TestSDKVersion = "17.6.0"; + TestSDKVersion = "17.12.0"; } } @@ -39,7 +39,7 @@ public class TestSDK_Preview : Collectors { public TestSDK_Preview() { - TestSDKVersion = "17.9.0-preview-23531-01"; + TestSDKVersion = "17.14.0-preview-25107-01"; } } diff --git a/test/coverlet.integration.tests/DeterministicBuild.cs b/test/coverlet.integration.tests/DeterministicBuild.cs index d9f4e326d..0cdad4cc2 100644 --- a/test/coverlet.integration.tests/DeterministicBuild.cs +++ b/test/coverlet.integration.tests/DeterministicBuild.cs @@ -13,6 +13,7 @@ namespace Coverlet.Integration.Tests { + [Collection("DeterministicBuild Collection")] public class DeterministicBuild : BaseTest, IDisposable { private static readonly string s_projectName = "coverlet.integration.determisticbuild"; @@ -432,4 +433,11 @@ public void Dispose() File.Delete(Path.Combine(_testProjectPath, PropsFileName)); } } + [CollectionDefinition("DeterministicBuild Collection", DisableParallelization = true)] + public class DeterministicBuildCollection + { + // This class has no code, and is never created. + // Its purpose is to be the place to apply [CollectionDefinition] and all the + // ICollectionFixture<> interfaces. + } } diff --git a/test/coverlet.tests.utils/TestUtils.cs b/test/coverlet.tests.utils/TestUtils.cs index 8a89196ac..af4777f82 100644 --- a/test/coverlet.tests.utils/TestUtils.cs +++ b/test/coverlet.tests.utils/TestUtils.cs @@ -33,11 +33,14 @@ public static BuildConfiguration GetAssemblyBuildConfiguration() public static string GetAssemblyTargetFramework() { +#if NET8_0 + return "net8.0"; +#endif #if NET9_0 return "net9.0"; #endif -#if NET8_0 - return "net8.0"; +#if NET10_0 + return "net10.0"; #endif throw new NotSupportedException($"Build configuration not supported"); } From 5b8cda0dbf7793c5f125a14548c0a6533370873c Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 20 Jul 2025 09:27:49 +0200 Subject: [PATCH 14/16] update .NET SDK and nuget package versions --- Directory.Packages.props | 6 +++--- eng/azure-pipelines-nightly.yml | 6 +++--- eng/build.yml | 6 +++--- global.json | 2 +- .../coverlet.integration.tests.csproj | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e4b2c0807..ab4d2bb54 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,11 +7,11 @@ - 17.13.26 + 17.11.31 4.13.0 6.14.0 - 17.13.0 + 17.14.1 2.0.0 3.1.0 @@ -55,7 +55,7 @@ - + diff --git a/eng/azure-pipelines-nightly.yml b/eng/azure-pipelines-nightly.yml index e2e8904da..3866dc503 100644 --- a/eng/azure-pipelines-nightly.yml +++ b/eng/azure-pipelines-nightly.yml @@ -4,13 +4,13 @@ pool: steps: - task: UseDotNet@2 inputs: - version: 8.0.408 - displayName: Install .NET Core SDK 8.0.408 + version: 8.0.412 + displayName: Install .NET Core SDK 8.0.412 - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 9.0.203 + displayName: Install .NET Core SDK (global.json) - task: NuGetAuthenticate@1 displayName: Authenticate with NuGet feeds diff --git a/eng/build.yml b/eng/build.yml index 301842a84..ba11764c7 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -1,13 +1,13 @@ steps: - task: UseDotNet@2 inputs: - version: 8.0.411 - displayName: Install .NET Core SDK 8.0.411 + version: 8.0.412 + displayName: Install .NET Core SDK 8.0.412 - task: UseDotNet@2 inputs: useGlobalJson: true - displayName: Install .NET Core SDK 9.0.301 + displayName: Install .NET Core SDK (global.json) # create artifact/package folder - pwsh: | diff --git a/global.json b/global.json index 1e11058e8..b2ead6c5d 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "9.0.301" + "version": "9.0.302" } } diff --git a/test/coverlet.integration.tests/coverlet.integration.tests.csproj b/test/coverlet.integration.tests/coverlet.integration.tests.csproj index 5a1e8f02e..cd247a1b2 100644 --- a/test/coverlet.integration.tests/coverlet.integration.tests.csproj +++ b/test/coverlet.integration.tests/coverlet.integration.tests.csproj @@ -22,7 +22,7 @@ all runtime; build; native; contentfiles; analyzers - + From 8009584546661720ab593abcac40c29d8fbe2bc3 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 20 Jul 2025 10:18:20 +0200 Subject: [PATCH 15/16] fix deprecated warning message --- Directory.Packages.props | 2 +- src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ab4d2bb54..780d63687 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -47,7 +47,7 @@ - + diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index cadaac8e3..8a1ce2736 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -42,6 +42,7 @@ + From e9904a583b0f600e55d51ba7aa1e58f32fc0e939 Mon Sep 17 00:00:00 2001 From: Bert Date: Wed, 23 Jul 2025 09:25:21 +0200 Subject: [PATCH 16/16] update xunit package version --- .gitignore | 2 ++ Directory.Packages.props | 6 ++++-- .../coverlet.core.coverage.tests.csproj | 2 +- .../coverlet.integration.tests.csproj | 1 + 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2179436d8..c87042b5d 100644 --- a/.gitignore +++ b/.gitignore @@ -319,3 +319,5 @@ FolderProfile.pubxml nuget.config *.dmp Playground*/ +#extended Playground +coverlet.MTP/ diff --git a/Directory.Packages.props b/Directory.Packages.props index 780d63687..6f16bf5a2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,8 +12,8 @@ 6.14.0 17.14.1 - 2.0.0 - 3.1.0 + 3.0.0 + 3.1.3 @@ -47,6 +47,8 @@ + + diff --git a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj index e95a53ece..006be0fbb 100644 --- a/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj +++ b/test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj @@ -22,7 +22,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/test/coverlet.integration.tests/coverlet.integration.tests.csproj b/test/coverlet.integration.tests/coverlet.integration.tests.csproj index cd247a1b2..0a0c5a469 100644 --- a/test/coverlet.integration.tests/coverlet.integration.tests.csproj +++ b/test/coverlet.integration.tests/coverlet.integration.tests.csproj @@ -22,6 +22,7 @@ all runtime; build; native; contentfiles; analyzers +