Add editorconfig with tuned configuration (#1300)

Add editorconfig with tuned configuration
This commit is contained in:
Amaury Levé
2022-02-14 09:14:38 +01:00
committed by GitHub
parent 1e74dd4382
commit 03ff455578
135 changed files with 1709 additions and 1161 deletions
+197
View File
@@ -0,0 +1,197 @@
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
# top-most EditorConfig file
root = true
###############################
# Core EditorConfig Options #
###############################
# All files
[*]
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
charset = utf-8
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# Xml build files
[*.builds]
indent_size = 2
# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2
# YAML config files
[*.{yml,yaml}]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
## IDE0005: Using directive is unnecessary.
dotnet_diagnostic.IDE0005.severity = warning
# License header
file_header_template = Copyright (c) Toni Solarin-Sodara\nLicensed under the MIT license. See LICENSE file in the project root for full license information.
## IDE0073: The file header is missing or not located at the top of the file
dotnet_diagnostic.IDE0073.severity = warning
# this. preferences
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:warning
## IDE0044: Add readonly modifier
dotnet_diagnostic.IDE0044.severity = warning
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Static fields should have s_ prefix
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case
# Internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
###############################
# C# Coding Conventions #
###############################
[*.cs]
# Organize usings
csharp_using_directive_placement = outside_namespace:warning
# var preferences - use keywords instead of BCL types, and permit var only when the type is clear
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = false:warning
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
csharp_style_prefer_not_pattern = true
## IDE0083: Use pattern matching
dotnet_diagnostic.IDE0083.severity = warning
# Null-checking preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:warning
## IDE0034: Simplify 'default' expression
dotnet_diagnostic.IDE0034.severity = warning
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:warning
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
dotnet_style_allow_multiple_blank_lines_experimental=false:warning
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
+3
View File
@@ -9,6 +9,9 @@
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>preview</AnalysisLevel>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<LangVersion>preview</LangVersion>
<NoWarn>$(NoWarn);NU5105</NoWarn>
<RestoreSources>
+5 -4
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28902.138
# Visual Studio Version 17
VisualStudioVersion = 17.2.32208.508
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}"
EndProject
@@ -27,6 +27,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsampl
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{77A15177-8262-488F-AF2B-91B9055715DA}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
eng\azure-pipelines-nightly.yml = eng\azure-pipelines-nightly.yml
eng\azure-pipelines.yml = eng\azure-pipelines.yml
@@ -53,9 +54,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{9A8B19D4
test\Directory.Build.targets = test\Directory.Build.targets
EndProjectSection
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "coverlet.tests.projectsample.fsharp", "test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj", "{1CBF6966-2A67-4D2C-8598-D174B83072F4}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "coverlet.tests.projectsample.fsharp", "test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj", "{1CBF6966-2A67-4D2C-8598-D174B83072F4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.tests.projectsample.netframework", "test\coverlet.tests.projectsample.netframework\coverlet.tests.projectsample.netframework.csproj", "{E69D68C9-78ED-4076-A14B-D07295A4B2A5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsample.netframework", "test\coverlet.tests.projectsample.netframework\coverlet.tests.projectsample.netframework.csproj", "{E69D68C9-78ED-4076-A14B-D07295A4B2A5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1,7 +1,9 @@
using System;
// 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.ComponentModel;
using System.IO;
using coverlet.collector.Resources;
using Coverlet.Collector.Utilities;
using Coverlet.Collector.Utilities.Interfaces;
@@ -50,7 +52,7 @@ namespace Coverlet.Collector.DataCollection
_reportDirectory = Path.Combine(Path.GetTempPath(), reportDirectoryName);
// Register events
_dataSink.SendFileCompleted += this.OnSendFileCompleted;
_dataSink.SendFileCompleted += OnSendFileCompleted;
}
/// <summary>
@@ -61,10 +63,10 @@ namespace Coverlet.Collector.DataCollection
public void SendCoverageReport(string coverageReport, string coverageReportFileName)
{
// Save coverage report to file
string coverageReportPath = this.SaveCoverageReport(coverageReport, coverageReportFileName);
string coverageReportPath = SaveCoverageReport(coverageReport, coverageReportFileName);
// Send coverage attachment to test platform.
this.SendAttachment(coverageReportPath);
SendAttachment(coverageReportPath);
}
/// <summary>
@@ -78,9 +80,9 @@ namespace Coverlet.Collector.DataCollection
_countDownEvent.Wait();
if (_dataSink != null)
{
_dataSink.SendFileCompleted -= this.OnSendFileCompleted;
_dataSink.SendFileCompleted -= OnSendFileCompleted;
}
this.CleanupReportDirectory();
CleanupReportDirectory();
}
catch (Exception ex)
{
@@ -1,4 +1,7 @@
using System;
// 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.Generic;
using System.IO;
using System.Linq;
@@ -77,8 +80,8 @@ namespace Coverlet.Collector.DataCollection
public IEnumerable<(string report, string fileName)> GetCoverageReports()
{
// Get coverage result
CoverageResult coverageResult = this.GetCoverageResult();
return this.GetCoverageReports(coverageResult);
CoverageResult coverageResult = GetCoverageResult();
return GetCoverageReports(coverageResult);
}
/// <summary>
@@ -1,4 +1,7 @@
using Coverlet.Collector.Utilities.Interfaces;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Coverlet.Collector.Utilities.Interfaces;
using Coverlet.Core;
using Coverlet.Core.Abstractions;
@@ -1,4 +1,7 @@
using System;
// 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.Generic;
using System.Diagnostics;
using System.Linq;
@@ -124,7 +127,7 @@ namespace Coverlet.Collector.DataCollection
try
{
// Get coverlet settings
IEnumerable<string> testModules = this.GetTestModules(sessionStartEventArgs);
IEnumerable<string> testModules = GetTestModules(sessionStartEventArgs);
var coverletSettingsParser = new CoverletSettingsParser(_eqtTrace);
CoverletSettings coverletSettings = coverletSettingsParser.Parse(_configurationElement, testModules);
@@ -142,7 +145,7 @@ namespace Coverlet.Collector.DataCollection
catch (Exception ex)
{
_logger.LogWarning(ex.ToString());
this.Dispose(true);
Dispose(true);
}
}
@@ -179,7 +182,7 @@ namespace Coverlet.Collector.DataCollection
catch (Exception ex)
{
_logger.LogWarning(ex.ToString());
this.Dispose(true);
Dispose(true);
}
}
@@ -1,5 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Coverlet.Collector.Utilities;
using Coverlet.Core.Abstractions;
@@ -1,4 +1,7 @@
using System.Linq;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Linq;
using System.Text;
namespace Coverlet.Collector.DataCollection
@@ -1,4 +1,7 @@
using System;
// 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.Generic;
using System.Linq;
using System.Xml;
@@ -89,7 +92,7 @@ namespace Coverlet.Collector.DataCollection
if (configurationElement != null)
{
XmlElement reportFormatElement = configurationElement[CoverletConstants.ReportFormatElementName];
formats = this.SplitElement(reportFormatElement);
formats = SplitElement(reportFormatElement);
}
return formats is null || formats.Length == 0 ? new[] { CoverletConstants.DefaultReportFormat } : formats;
@@ -103,7 +106,7 @@ namespace Coverlet.Collector.DataCollection
private string[] ParseIncludeFilters(XmlElement configurationElement)
{
XmlElement includeFiltersElement = configurationElement[CoverletConstants.IncludeFiltersElementName];
return this.SplitElement(includeFiltersElement);
return SplitElement(includeFiltersElement);
}
/// <summary>
@@ -114,7 +117,7 @@ namespace Coverlet.Collector.DataCollection
private string[] ParseIncludeDirectories(XmlElement configurationElement)
{
XmlElement includeDirectoriesElement = configurationElement[CoverletConstants.IncludeDirectoriesElementName];
return this.SplitElement(includeDirectoriesElement);
return SplitElement(includeDirectoriesElement);
}
/// <summary>
@@ -124,12 +127,12 @@ namespace Coverlet.Collector.DataCollection
/// <returns>Filters to exclude</returns>
private string[] ParseExcludeFilters(XmlElement configurationElement)
{
List<string> excludeFilters = new List<string> { CoverletConstants.DefaultExcludeFilter };
var excludeFilters = new List<string> { CoverletConstants.DefaultExcludeFilter };
if (configurationElement != null)
{
XmlElement excludeFiltersElement = configurationElement[CoverletConstants.ExcludeFiltersElementName];
string[] filters = this.SplitElement(excludeFiltersElement);
string[] filters = SplitElement(excludeFiltersElement);
if (filters != null)
{
excludeFilters.AddRange(filters);
@@ -147,7 +150,7 @@ namespace Coverlet.Collector.DataCollection
private string[] ParseExcludeSourceFiles(XmlElement configurationElement)
{
XmlElement excludeSourceFilesElement = configurationElement[CoverletConstants.ExcludeSourceFilesElementName];
return this.SplitElement(excludeSourceFilesElement);
return SplitElement(excludeSourceFilesElement);
}
/// <summary>
@@ -158,7 +161,7 @@ namespace Coverlet.Collector.DataCollection
private string[] ParseExcludeAttributes(XmlElement configurationElement)
{
XmlElement excludeAttributesElement = configurationElement[CoverletConstants.ExcludeAttributesElementName];
return this.SplitElement(excludeAttributesElement);
return SplitElement(excludeAttributesElement);
}
/// <summary>
@@ -240,7 +243,7 @@ namespace Coverlet.Collector.DataCollection
private string[] ParseDoesNotReturnAttributes(XmlElement configurationElement)
{
XmlElement doesNotReturnAttributesElement = configurationElement[CoverletConstants.DoesNotReturnAttributesElementName];
return this.SplitElement(doesNotReturnAttributesElement);
return SplitElement(doesNotReturnAttributesElement);
}
/// <summary>
@@ -1,8 +1,10 @@
using System;
// 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.Diagnostics;
using System.Reflection;
using System.Text;
using coverlet.collector.Resources;
using Coverlet.Collector.Utilities;
using Coverlet.Core.Instrumentation;
@@ -53,7 +55,7 @@ namespace Coverlet.Collector.DataCollection
public void TestSessionEnd(TestSessionEndArgs testSessionEndArgs)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type injectedInstrumentationClass = GetInstrumentationClass(assembly);
if (injectedInstrumentationClass is null)
@@ -64,7 +66,7 @@ namespace Coverlet.Collector.DataCollection
try
{
_eqtTrace.Verbose($"Calling ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
var unloadModule = injectedInstrumentationClass.GetMethod(nameof(ModuleTrackerTemplate.UnloadModule), new[] { typeof(object), typeof(EventArgs) });
MethodInfo unloadModule = injectedInstrumentationClass.GetMethod(nameof(ModuleTrackerTemplate.UnloadModule), new[] { typeof(object), typeof(EventArgs) });
unloadModule.Invoke(null, new[] { (object)this, EventArgs.Empty });
injectedInstrumentationClass.GetField("FlushHitFile", BindingFlags.Static | BindingFlags.Public).SetValue(null, false);
_eqtTrace.Verbose($"Called ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
@@ -89,7 +91,7 @@ namespace Coverlet.Collector.DataCollection
{
try
{
foreach (var type in assembly.GetTypes())
foreach (Type type in assembly.GetTypes())
{
if (type.Namespace == "Coverlet.Core.Instrumentation.Tracker"
&& type.Name.StartsWith(assembly.GetName().Name + "_"))
@@ -104,7 +106,7 @@ namespace Coverlet.Collector.DataCollection
{
if (_enableExceptionLog)
{
StringBuilder exceptionString = new StringBuilder();
var exceptionString = new StringBuilder();
exceptionString.AppendFormat("{0}: Failed to get Instrumentation class for assembly '{1}' with error: {2}",
CoverletConstants.InProcDataCollectorName, assembly, ex);
exceptionString.AppendLine();
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -1,6 +1,8 @@
using System;
using System.Threading;
// 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.Threading;
using Coverlet.Collector.Utilities.Interfaces;
namespace Coverlet.Collector.Utilities
@@ -1,4 +1,7 @@
namespace Coverlet.Collector.Utilities
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Collector.Utilities
{
internal static class CoverletConstants
{
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Collector.Utilities
{
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using Coverlet.Collector.Utilities.Interfaces;
namespace Coverlet.Collector.Utilities
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using Coverlet.Collector.Utilities.Interfaces;
namespace Coverlet.Collector.Utilities
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Collector.Utilities.Interfaces
{
@@ -1,4 +1,7 @@
using Coverlet.Collector.DataCollection;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Coverlet.Collector.DataCollection;
using Coverlet.Core;
using Coverlet.Core.Abstractions;
@@ -1,4 +1,7 @@
namespace Coverlet.Collector.Utilities.Interfaces
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Collector.Utilities.Interfaces
{
interface IDirectoryHelper
{
@@ -1,4 +1,7 @@
namespace Coverlet.Collector.Utilities.Interfaces
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Collector.Utilities.Interfaces
{
internal interface IFileHelper
{
@@ -1,4 +1,7 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
namespace Coverlet.Collector.Utilities
{
@@ -1,4 +1,7 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
namespace Coverlet.Collector.Utilities
{
@@ -0,0 +1,8 @@
# top-most EditorConfig file
# We don't want to import other EditorConfig files and we want
# to ensure no rules are enabled for these asset source files.
root = true
[*.cs]
# Default severity for all analyzer diagnostics
dotnet_analyzer_diagnostic.severity = none
+4 -1
View File
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
/// <summary>
/// Exit Codes returned from Coverlet console process.
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Coverlet.Core.Abstractions;
using static System.Console;
+3
View File
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Console.Logging
{
/// <summary>
+35 -33
View File
@@ -1,4 +1,7 @@
using System;
// 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.Generic;
using System.ComponentModel;
using System.Diagnostics;
@@ -6,7 +9,6 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using ConsoleTables;
using Coverlet.Console.Logging;
using Coverlet.Core;
@@ -37,7 +39,7 @@ namespace Coverlet.Console
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var logger = (ConsoleLogger)serviceProvider.GetService<ILogger>();
var fileSystem = serviceProvider.GetService<IFileSystem>();
IFileSystem fileSystem = serviceProvider.GetService<IFileSystem>();
var app = new CommandLineApplication
{
@@ -134,15 +136,15 @@ namespace Coverlet.Console
process.WaitForExit();
var dOutput = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
var dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List<string>(new string[] { "line", "branch", "method" });
var dThresholdStat = thresholdStat.HasValue() ? Enum.Parse<ThresholdStatistic>(thresholdStat.Value(), true) : Enum.Parse<ThresholdStatistic>("minimum", true);
string dOutput = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
List<string> dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List<string>(new string[] { "line", "branch", "method" });
ThresholdStatistic dThresholdStat = thresholdStat.HasValue() ? Enum.Parse<ThresholdStatistic>(thresholdStat.Value(), true) : Enum.Parse<ThresholdStatistic>("minimum", true);
logger.LogInformation("\nCalculating coverage result...");
var result = coverage.GetCoverageResult();
CoverageResult result = coverage.GetCoverageResult();
var directory = Path.GetDirectoryName(dOutput);
string directory = Path.GetDirectoryName(dOutput);
if (directory == string.Empty)
{
directory = Directory.GetCurrentDirectory();
@@ -152,9 +154,9 @@ namespace Coverlet.Console
Directory.CreateDirectory(directory);
}
foreach (var format in formats.HasValue() ? formats.Values : new List<string>(new string[] { "json" }))
foreach (string format in formats.HasValue() ? formats.Values : new List<string>(new string[] { "json" }))
{
var reporter = new ReporterFactory(format).CreateReporter();
Core.Abstractions.IReporter reporter = new ReporterFactory(format).CreateReporter();
if (reporter == null)
{
throw new Exception($"Specified output format '{format}' is not supported");
@@ -169,11 +171,11 @@ namespace Coverlet.Console
else
{
// Output to file
var filename = Path.GetFileName(dOutput);
string filename = Path.GetFileName(dOutput);
filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
filename = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";
var report = Path.Combine(directory, filename);
string report = Path.Combine(directory, filename);
logger.LogInformation($" Generating report '{report}'", important: true);
fileSystem.WriteAllText(report, reporter.Report(result, sourceRootTranslator));
}
@@ -181,7 +183,7 @@ namespace Coverlet.Console
var thresholdTypeFlagQueue = new Queue<ThresholdTypeFlags>();
foreach (var thresholdType in dThresholdTypes)
foreach (string thresholdType in dThresholdTypes)
{
if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
{
@@ -197,18 +199,18 @@ namespace Coverlet.Console
}
}
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>();
if (threshold.HasValue() && threshold.Value().Contains(','))
{
var thresholdValues = threshold.Value().Split(',', StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
if (thresholdValues.Count() != thresholdTypeFlagQueue.Count())
IEnumerable<string> thresholdValues = threshold.Value().Split(',', StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
if (thresholdValues.Count() != thresholdTypeFlagQueue.Count)
{
throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count()}) and values count ({thresholdValues.Count()}) doesn't match");
throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count}) and values count ({thresholdValues.Count()}) doesn't match");
}
foreach (var thresholdValue in thresholdValues)
foreach (string thresholdValue in thresholdValues)
{
if (double.TryParse(thresholdValue, out var value))
if (double.TryParse(thresholdValue, out double value))
{
thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
}
@@ -231,23 +233,23 @@ namespace Coverlet.Console
var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
var summary = new CoverageSummary();
var linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
CoverageDetails linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
CoverageDetails branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
CoverageDetails methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
var totalLinePercent = linePercentCalculation.Percent;
var totalBranchPercent = branchPercentCalculation.Percent;
var totalMethodPercent = methodPercentCalculation.Percent;
double totalLinePercent = linePercentCalculation.Percent;
double totalBranchPercent = branchPercentCalculation.Percent;
double totalMethodPercent = methodPercentCalculation.Percent;
var averageLinePercent = linePercentCalculation.AverageModulePercent;
var averageBranchPercent = branchPercentCalculation.AverageModulePercent;
var averageMethodPercent = methodPercentCalculation.AverageModulePercent;
double averageLinePercent = linePercentCalculation.AverageModulePercent;
double averageBranchPercent = branchPercentCalculation.AverageModulePercent;
double averageMethodPercent = methodPercentCalculation.AverageModulePercent;
foreach (var _module in result.Modules)
foreach (KeyValuePair<string, Documents> _module in result.Modules)
{
var linePercent = summary.CalculateLineCoverage(_module.Value).Percent;
var branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
var methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;
double linePercent = summary.CalculateLineCoverage(_module.Value).Percent;
double branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
double methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;
coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
}
@@ -267,7 +269,7 @@ namespace Coverlet.Console
exitCode += (int)CommandExitCodes.TestFailed;
}
var thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, dThresholdStat);
ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, dThresholdStat);
if (thresholdTypeFlags != ThresholdTypeFlags.None)
{
exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
@@ -1 +1,4 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
[assembly: System.Reflection.AssemblyKeyFileAttribute("coverlet.console.snk")]
@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Coverlet.Core.Symbols;
using Mono.Cecil;
using Mono.Cecil.Cil;
+4 -1
View File
@@ -1,4 +1,7 @@
namespace Coverlet.Core.Abstractions
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Abstractions
{
internal interface IConsole
{
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
namespace Coverlet.Core.Abstractions
{
@@ -1,4 +1,7 @@
namespace Coverlet.Core.Abstractions
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Abstractions
{
internal interface IInstrumentationHelper
{
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Abstractions
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Abstractions
{
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Abstractions
{
internal interface IReporter
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Abstractions
{
@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Coverlet.Core.Helpers;
namespace Coverlet.Core.Abstractions
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Attributes
{
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Attributes
+53 -55
View File
@@ -1,3 +1,6 @@
// 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.Generic;
using System.IO;
@@ -6,7 +9,6 @@ using System.Runtime.Serialization;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Instrumentation;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -45,20 +47,16 @@ namespace Coverlet.Core
internal class Coverage
{
private string _moduleOrAppDirectory;
private string _identifier;
private ILogger _logger;
private IInstrumentationHelper _instrumentationHelper;
private IFileSystem _fileSystem;
private ISourceRootTranslator _sourceRootTranslator;
private ICecilSymbolHelper _cecilSymbolHelper;
private List<InstrumenterResult> _results;
private CoverageParameters _parameters;
private readonly string _moduleOrAppDirectory;
private readonly ILogger _logger;
private readonly IInstrumentationHelper _instrumentationHelper;
private readonly IFileSystem _fileSystem;
private readonly ISourceRootTranslator _sourceRootTranslator;
private readonly ICecilSymbolHelper _cecilSymbolHelper;
private readonly List<InstrumenterResult> _results;
private readonly CoverageParameters _parameters;
public string Identifier
{
get { return _identifier; }
}
public string Identifier { get; }
public Coverage(string moduleOrDirectory,
CoverageParameters parameters,
@@ -76,7 +74,7 @@ namespace Coverlet.Core
_fileSystem = fileSystem;
_sourceRootTranslator = sourceRootTranslator;
_cecilSymbolHelper = cecilSymbolHelper;
_identifier = Guid.NewGuid().ToString();
Identifier = Guid.NewGuid().ToString();
_results = new List<InstrumenterResult>();
}
@@ -86,7 +84,7 @@ namespace Coverlet.Core
IFileSystem fileSystem,
ISourceRootTranslator sourceRootTranslator)
{
_identifier = prepareResult.Identifier;
Identifier = prepareResult.Identifier;
_moduleOrAppDirectory = prepareResult.ModuleOrDirectory;
_parameters = prepareResult.Parameters;
_results = new List<InstrumenterResult>(prepareResult.Results);
@@ -107,7 +105,7 @@ namespace Coverlet.Core
_parameters.ExcludeFilters = _parameters.ExcludeFilters?.Where(f => _instrumentationHelper.IsValidFilterExpression(f)).ToArray();
_parameters.IncludeFilters = _parameters.IncludeFilters?.Where(f => _instrumentationHelper.IsValidFilterExpression(f)).ToArray();
foreach (var module in modules)
foreach (string module in modules)
{
if (_instrumentationHelper.IsModuleExcluded(module, _parameters.ExcludeFilters) ||
!_instrumentationHelper.IsModuleIncluded(module, _parameters.IncludeFilters))
@@ -117,7 +115,7 @@ namespace Coverlet.Core
}
var instrumenter = new Instrumenter(module,
_identifier,
Identifier,
_parameters,
_logger,
_instrumentationHelper,
@@ -127,7 +125,7 @@ namespace Coverlet.Core
if (instrumenter.CanInstrument())
{
_instrumentationHelper.BackupOriginalModule(module, _identifier);
_instrumentationHelper.BackupOriginalModule(module, Identifier);
// Guard code path and restore if instrumentation fails.
try
@@ -142,14 +140,14 @@ namespace Coverlet.Core
catch (Exception ex)
{
_logger.LogWarning($"Unable to instrument module: {module}\n{ex}");
_instrumentationHelper.RestoreOriginalModule(module, _identifier);
_instrumentationHelper.RestoreOriginalModule(module, Identifier);
}
}
}
return new CoveragePrepareResult()
{
Identifier = _identifier,
Identifier = Identifier,
ModuleOrDirectory = _moduleOrAppDirectory,
Parameters = _parameters,
Results = _results.ToArray()
@@ -160,14 +158,14 @@ namespace Coverlet.Core
{
CalculateCoverage();
Modules modules = new Modules();
foreach (var result in _results)
var modules = new Modules();
foreach (InstrumenterResult result in _results)
{
Documents documents = new Documents();
foreach (var doc in result.Documents.Values)
var documents = new Documents();
foreach (Document doc in result.Documents.Values)
{
// Construct Line Results
foreach (var line in doc.Lines.Values)
foreach (Line line in doc.Lines.Values)
{
if (documents.TryGetValue(doc.Path, out Classes classes))
{
@@ -200,7 +198,7 @@ namespace Coverlet.Core
}
// Construct Branch Results
foreach (var branch in doc.Branches.Values)
foreach (Branch branch in doc.Branches.Values)
{
if (documents.TryGetValue(doc.Path, out Classes classes))
{
@@ -242,7 +240,7 @@ namespace Coverlet.Core
}
modules.Add(Path.GetFileName(result.ModulePath), documents);
_instrumentationHelper.RestoreOriginalModule(result.ModulePath, _identifier);
_instrumentationHelper.RestoreOriginalModule(result.ModulePath, Identifier);
}
// In case of anonymous delegate compiler generate a custom class and passes it as type.method delegate.
@@ -250,11 +248,11 @@ namespace Coverlet.Core
// We search "method" with same "Line" of closure class method and add missing branches to it,
// in this way we correctly report missing branch inside compiled generated anonymous delegate.
List<string> compileGeneratedClassToRemove = null;
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
foreach (var document in module.Value)
foreach (KeyValuePair<string, Classes> document in module.Value)
{
foreach (var @class in document.Value)
foreach (KeyValuePair<string, Methods> @class in document.Value)
{
// We fix only lamda generated class
// https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs#L18
@@ -263,9 +261,9 @@ namespace Coverlet.Core
continue;
}
foreach (var method in @class.Value)
foreach (KeyValuePair<string, Method> method in @class.Value)
{
foreach (var branch in method.Value.Branches)
foreach (BranchInfo branch in method.Value.Branches)
{
if (BranchInCompilerGeneratedClass(method.Key))
{
@@ -295,13 +293,13 @@ namespace Coverlet.Core
}
// After method/branches analysis of compiled generated class we can remove noise from reports
if (!(compileGeneratedClassToRemove is null))
if (compileGeneratedClassToRemove is not null)
{
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
foreach (var document in module.Value)
foreach (KeyValuePair<string, Classes> document in module.Value)
{
foreach (var classToRemove in compileGeneratedClassToRemove)
foreach (string classToRemove in compileGeneratedClassToRemove)
{
document.Value.Remove(classToRemove);
}
@@ -309,7 +307,7 @@ namespace Coverlet.Core
}
}
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results, Parameters = _parameters };
var coverageResult = new CoverageResult { Identifier = Identifier, Modules = modules, InstrumentedResults = _results, Parameters = _parameters };
if (!string.IsNullOrEmpty(_parameters.MergeWith) && !string.IsNullOrWhiteSpace(_parameters.MergeWith) && _fileSystem.Exists(_parameters.MergeWith))
{
@@ -322,7 +320,7 @@ namespace Coverlet.Core
private bool BranchInCompilerGeneratedClass(string methodName)
{
foreach (var instrumentedResult in _results)
foreach (InstrumenterResult instrumentedResult in _results)
{
if (instrumentedResult.BranchesInCompiledGeneratedClass.Contains(methodName))
{
@@ -334,16 +332,16 @@ namespace Coverlet.Core
private Method GetMethodWithSameLineInSameDocument(Classes documentClasses, string compilerGeneratedClassName, int branchLine)
{
foreach (var @class in documentClasses)
foreach (KeyValuePair<string, Methods> @class in documentClasses)
{
if (@class.Key == compilerGeneratedClassName)
{
continue;
}
foreach (var method in @class.Value)
foreach (KeyValuePair<string, Method> method in @class.Value)
{
foreach (var line in method.Value.Lines)
foreach (KeyValuePair<int, int> line in method.Value.Lines)
{
if (line.Key == branchLine)
{
@@ -357,7 +355,7 @@ namespace Coverlet.Core
private void CalculateCoverage()
{
foreach (var result in _results)
foreach (InstrumenterResult result in _results)
{
if (!_fileSystem.Exists(result.HitsFilePath))
{
@@ -369,12 +367,12 @@ namespace Coverlet.Core
continue;
}
List<Document> documents = result.Documents.Values.ToList();
var documents = result.Documents.Values.ToList();
if (_parameters.UseSourceLink && result.SourceLink != null)
{
var jObject = JObject.Parse(result.SourceLink)["documents"];
var sourceLinkDocuments = JsonConvert.DeserializeObject<Dictionary<string, string>>(jObject.ToString());
foreach (var document in documents)
JToken jObject = JObject.Parse(result.SourceLink)["documents"];
Dictionary<string, string> sourceLinkDocuments = JsonConvert.DeserializeObject<Dictionary<string, string>>(jObject.ToString());
foreach (Document document in documents)
{
document.Path = GetSourceLinkUrl(sourceLinkDocuments, document.Path);
}
@@ -408,7 +406,7 @@ namespace Coverlet.Core
}
var documentsList = result.Documents.Values.ToList();
using (var fs = _fileSystem.NewFileStream(result.HitsFilePath, FileMode.Open, FileAccess.Read))
using (Stream fs = _fileSystem.NewFileStream(result.HitsFilePath, FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(fs))
{
int hitCandidatesCount = br.ReadInt32();
@@ -417,8 +415,8 @@ namespace Coverlet.Core
for (int i = 0; i < hitCandidatesCount; ++i)
{
var hitLocation = result.HitCandidates[i];
var document = documentsList[hitLocation.docIndex];
HitCandidate hitLocation = result.HitCandidates[i];
Document document = documentsList[hitLocation.docIndex];
int hits = br.ReadInt32();
if (hits == 0)
@@ -428,7 +426,7 @@ namespace Coverlet.Core
if (hitLocation.isBranch)
{
var branch = document.Branches[new BranchKey(hitLocation.start, hitLocation.end)];
Branch branch = document.Branches[new BranchKey(hitLocation.start, hitLocation.end)];
branch.Hits += hits;
if (branch.Hits < 0)
@@ -443,7 +441,7 @@ namespace Coverlet.Core
continue;
}
var line = document.Lines[j];
Line line = document.Lines[j];
line.Hits += hits;
if (line.Hits < 0)
@@ -472,10 +470,10 @@ namespace Coverlet.Core
return url;
}
var keyWithBestMatch = string.Empty;
var relativePathOfBestMatch = string.Empty;
string keyWithBestMatch = string.Empty;
string relativePathOfBestMatch = string.Empty;
foreach (var sourceLinkDocument in sourceLinkDocuments)
foreach (KeyValuePair<string, string> sourceLinkDocument in sourceLinkDocuments)
{
string key = sourceLinkDocument.Key;
if (Path.GetFileName(key) != "*") continue;
+3
View File
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core
+5 -2
View File
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Runtime.Serialization;
using Coverlet.Core.Instrumentation;
@@ -30,7 +33,7 @@ namespace Coverlet.Core
public static Stream Serialize(CoveragePrepareResult instrumentState)
{
MemoryStream ms = new MemoryStream();
var ms = new MemoryStream();
new DataContractSerializer(typeof(CoveragePrepareResult)).WriteObject(ms, instrumentState);
ms.Position = 0;
return ms;
+27 -27
View File
@@ -1,10 +1,10 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Coverlet.Core.Enums;
using Coverlet.Core.Instrumentation;
using Coverlet.Core.Symbols;
namespace Coverlet.Core
{
@@ -48,54 +48,54 @@ namespace Coverlet.Core
public void Merge(Modules modules)
{
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
if (!this.Modules.Keys.Contains(module.Key))
if (!Modules.Keys.Contains(module.Key))
{
this.Modules.Add(module.Key, module.Value);
Modules.Add(module.Key, module.Value);
}
else
{
foreach (var document in module.Value)
foreach (KeyValuePair<string, Classes> document in module.Value)
{
if (!this.Modules[module.Key].ContainsKey(document.Key))
if (!Modules[module.Key].ContainsKey(document.Key))
{
this.Modules[module.Key].Add(document.Key, document.Value);
Modules[module.Key].Add(document.Key, document.Value);
}
else
{
foreach (var @class in document.Value)
foreach (KeyValuePair<string, Methods> @class in document.Value)
{
if (!this.Modules[module.Key][document.Key].ContainsKey(@class.Key))
if (!Modules[module.Key][document.Key].ContainsKey(@class.Key))
{
this.Modules[module.Key][document.Key].Add(@class.Key, @class.Value);
Modules[module.Key][document.Key].Add(@class.Key, @class.Value);
}
else
{
foreach (var method in @class.Value)
foreach (KeyValuePair<string, Method> method in @class.Value)
{
if (!this.Modules[module.Key][document.Key][@class.Key].ContainsKey(method.Key))
if (!Modules[module.Key][document.Key][@class.Key].ContainsKey(method.Key))
{
this.Modules[module.Key][document.Key][@class.Key].Add(method.Key, method.Value);
Modules[module.Key][document.Key][@class.Key].Add(method.Key, method.Value);
}
else
{
foreach (var line in method.Value.Lines)
foreach (KeyValuePair<int, int> line in method.Value.Lines)
{
if (!this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines.ContainsKey(line.Key))
if (!Modules[module.Key][document.Key][@class.Key][method.Key].Lines.ContainsKey(line.Key))
{
this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines.Add(line.Key, line.Value);
Modules[module.Key][document.Key][@class.Key][method.Key].Lines.Add(line.Key, line.Value);
}
else
{
this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines[line.Key] += line.Value;
Modules[module.Key][document.Key][@class.Key][method.Key].Lines[line.Key] += line.Value;
}
}
foreach (var branch in method.Value.Branches)
foreach (BranchInfo branch in method.Value.Branches)
{
var branches = this.Modules[module.Key][document.Key][@class.Key][method.Key].Branches;
var branchInfo = branches.FirstOrDefault(b => b.EndOffset == branch.EndOffset && b.Line == branch.Line && b.Offset == branch.Offset && b.Ordinal == branch.Ordinal && b.Path == branch.Path);
Branches branches = Modules[module.Key][document.Key][@class.Key][method.Key].Branches;
BranchInfo branchInfo = branches.FirstOrDefault(b => b.EndOffset == branch.EndOffset && b.Line == branch.Line && b.Offset == branch.Offset && b.Ordinal == branch.Ordinal && b.Path == branch.Path);
if (branchInfo == null)
branches.Add(branch);
else
@@ -113,7 +113,7 @@ namespace Coverlet.Core
public ThresholdTypeFlags GetThresholdTypesBelowThreshold(CoverageSummary summary, Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues, ThresholdStatistic thresholdStat)
{
var thresholdTypeFlags = ThresholdTypeFlags.None;
ThresholdTypeFlags thresholdTypeFlags = ThresholdTypeFlags.None;
switch (thresholdStat)
{
case ThresholdStatistic.Minimum:
@@ -121,7 +121,7 @@ namespace Coverlet.Core
if (!Modules.Any())
thresholdTypeFlags = CompareThresholdValues(thresholdTypeFlagValues, thresholdTypeFlags, 0, 0, 0);
foreach (var module in Modules)
foreach (KeyValuePair<string, Documents> module in Modules)
{
double line = summary.CalculateLineCoverage(module.Value).Percent;
double branch = summary.CalculateBranchCoverage(module.Value).Percent;
@@ -158,19 +158,19 @@ namespace Coverlet.Core
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues, ThresholdTypeFlags thresholdTypeFlags,
double line, double branch, double method)
{
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Line, out var lineThresholdValue) &&
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Line, out double lineThresholdValue) &&
lineThresholdValue > line)
{
thresholdTypeFlags |= ThresholdTypeFlags.Line;
}
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Branch, out var branchThresholdValue) &&
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Branch, out double branchThresholdValue) &&
branchThresholdValue > branch)
{
thresholdTypeFlags |= ThresholdTypeFlags.Branch;
}
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Method, out var methodThresholdValue) &&
if (thresholdTypeFlagValues.TryGetValue(ThresholdTypeFlags.Method, out double methodThresholdValue) &&
methodThresholdValue > method)
{
thresholdTypeFlags |= ThresholdTypeFlags.Method;
+33 -30
View File
@@ -1,3 +1,6 @@
// 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.Generic;
using System.Linq;
@@ -17,9 +20,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateLineCoverage(Methods methods)
{
var details = new CoverageDetails();
foreach (var method in methods)
foreach (KeyValuePair<string, Method> method in methods)
{
var methodCoverage = CalculateLineCoverage(method.Value.Lines);
CoverageDetails methodCoverage = CalculateLineCoverage(method.Value.Lines);
details.Covered += methodCoverage.Covered;
details.Total += methodCoverage.Total;
}
@@ -29,9 +32,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateLineCoverage(Classes classes)
{
var details = new CoverageDetails();
foreach (var @class in classes)
foreach (KeyValuePair<string, Methods> @class in classes)
{
var classCoverage = CalculateLineCoverage(@class.Value);
CoverageDetails classCoverage = CalculateLineCoverage(@class.Value);
details.Covered += classCoverage.Covered;
details.Total += classCoverage.Total;
}
@@ -41,9 +44,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateLineCoverage(Documents documents)
{
var details = new CoverageDetails();
foreach (var document in documents)
foreach (KeyValuePair<string, Classes> document in documents)
{
var documentCoverage = CalculateLineCoverage(document.Value);
CoverageDetails documentCoverage = CalculateLineCoverage(document.Value);
details.Covered += documentCoverage.Covered;
details.Total += documentCoverage.Total;
}
@@ -53,14 +56,14 @@ namespace Coverlet.Core
public CoverageDetails CalculateLineCoverage(Modules modules)
{
var details = new CoverageDetails { Modules = modules };
var accumPercent = 0.0D;
double accumPercent = 0.0D;
if (modules.Count == 0)
return details;
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
var moduleCoverage = CalculateLineCoverage(module.Value);
CoverageDetails moduleCoverage = CalculateLineCoverage(module.Value);
details.Covered += moduleCoverage.Covered;
details.Total += moduleCoverage.Total;
accumPercent += moduleCoverage.Percent;
@@ -86,7 +89,7 @@ namespace Coverlet.Core
}
var paths = new Dictionary<int, int>();
foreach (var branch in branches)
foreach (BranchInfo branch in branches)
{
if (!paths.TryGetValue(branch.Offset, out int count))
{
@@ -96,7 +99,7 @@ namespace Coverlet.Core
}
int npath = 1;
foreach (var branchPoints in paths.Values)
foreach (int branchPoints in paths.Values)
{
try
{
@@ -154,9 +157,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateBranchCoverage(Methods methods)
{
var details = new CoverageDetails();
foreach (var method in methods)
foreach (KeyValuePair<string, Method> method in methods)
{
var methodCoverage = CalculateBranchCoverage(method.Value.Branches);
CoverageDetails methodCoverage = CalculateBranchCoverage(method.Value.Branches);
details.Covered += methodCoverage.Covered;
details.Total += methodCoverage.Total;
}
@@ -166,9 +169,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateBranchCoverage(Classes classes)
{
var details = new CoverageDetails();
foreach (var @class in classes)
foreach (KeyValuePair<string, Methods> @class in classes)
{
var classCoverage = CalculateBranchCoverage(@class.Value);
CoverageDetails classCoverage = CalculateBranchCoverage(@class.Value);
details.Covered += classCoverage.Covered;
details.Total += classCoverage.Total;
}
@@ -178,9 +181,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateBranchCoverage(Documents documents)
{
var details = new CoverageDetails();
foreach (var document in documents)
foreach (KeyValuePair<string, Classes> document in documents)
{
var documentCoverage = CalculateBranchCoverage(document.Value);
CoverageDetails documentCoverage = CalculateBranchCoverage(document.Value);
details.Covered += documentCoverage.Covered;
details.Total += documentCoverage.Total;
}
@@ -190,14 +193,14 @@ namespace Coverlet.Core
public CoverageDetails CalculateBranchCoverage(Modules modules)
{
var details = new CoverageDetails { Modules = modules };
var accumPercent = 0.0D;
double accumPercent = 0.0D;
if (modules.Count == 0)
return details;
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
var moduleCoverage = CalculateBranchCoverage(module.Value);
CoverageDetails moduleCoverage = CalculateBranchCoverage(module.Value);
details.Covered += moduleCoverage.Covered;
details.Total += moduleCoverage.Total;
accumPercent += moduleCoverage.Percent;
@@ -217,10 +220,10 @@ namespace Coverlet.Core
public CoverageDetails CalculateMethodCoverage(Methods methods)
{
var details = new CoverageDetails();
var methodsWithLines = methods.Where(m => m.Value.Lines.Count > 0);
foreach (var method in methodsWithLines)
IEnumerable<KeyValuePair<string, Method>> methodsWithLines = methods.Where(m => m.Value.Lines.Count > 0);
foreach (KeyValuePair<string, Method> method in methodsWithLines)
{
var methodCoverage = CalculateMethodCoverage(method.Value.Lines);
CoverageDetails methodCoverage = CalculateMethodCoverage(method.Value.Lines);
details.Covered += methodCoverage.Covered;
}
details.Total = methodsWithLines.Count();
@@ -230,9 +233,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateMethodCoverage(Classes classes)
{
var details = new CoverageDetails();
foreach (var @class in classes)
foreach (KeyValuePair<string, Methods> @class in classes)
{
var classCoverage = CalculateMethodCoverage(@class.Value);
CoverageDetails classCoverage = CalculateMethodCoverage(@class.Value);
details.Covered += classCoverage.Covered;
details.Total += classCoverage.Total;
}
@@ -242,9 +245,9 @@ namespace Coverlet.Core
public CoverageDetails CalculateMethodCoverage(Documents documents)
{
var details = new CoverageDetails();
foreach (var document in documents)
foreach (KeyValuePair<string, Classes> document in documents)
{
var documentCoverage = CalculateMethodCoverage(document.Value);
CoverageDetails documentCoverage = CalculateMethodCoverage(document.Value);
details.Covered += documentCoverage.Covered;
details.Total += documentCoverage.Total;
}
@@ -254,14 +257,14 @@ namespace Coverlet.Core
public CoverageDetails CalculateMethodCoverage(Modules modules)
{
var details = new CoverageDetails { Modules = modules };
var accumPercent = 0.0D;
double accumPercent = 0.0D;
if (modules.Count == 0)
return details;
foreach (var module in modules)
foreach (KeyValuePair<string, Documents> module in modules)
{
var moduleCoverage = CalculateMethodCoverage(module.Value);
CoverageDetails moduleCoverage = CalculateMethodCoverage(module.Value);
details.Covered += moduleCoverage.Covered;
details.Total += moduleCoverage.Total;
accumPercent += moduleCoverage.Percent;
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Enums
{
internal enum ThresholdStatistic
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Enums
+4 -1
View File
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Exceptions
{
@@ -1,3 +1,5 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Coverlet.Core.Attributes;
@@ -7,7 +9,7 @@ namespace Coverlet.Core.Extensions
internal static class HelperExtensions
{
[ExcludeFromCoverage]
public static TRet Maybe<T, TRet>(this T value, Func<T, TRet> action, TRet defValue = default(TRet))
public static TRet Maybe<T, TRet>(this T value, Func<T, TRet> action, TRet defValue = default)
where T : class
{
return (value != null) ? action(value) : defValue;
+3 -1
View File
@@ -1,5 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
+4 -1
View File
@@ -1,5 +1,8 @@
using Coverlet.Core.Abstractions;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
{
@@ -1,3 +1,6 @@
// 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.Concurrent;
using System.Collections.Generic;
@@ -8,7 +11,6 @@ using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Text.RegularExpressions;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
@@ -81,14 +83,14 @@ namespace Coverlet.Core.Helpers
public bool HasPdb(string module, out bool embedded)
{
embedded = false;
using (var moduleStream = _fileSystem.OpenRead(module))
using (Stream moduleStream = _fileSystem.OpenRead(module))
using (var peReader = new PEReader(moduleStream))
{
foreach (var entry in peReader.ReadDebugDirectory())
foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
{
if (entry.Type == DebugDirectoryEntryType.CodeView)
{
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
if (_sourceRootTranslator.ResolveFilePath(codeViewData.Path) == $"{Path.GetFileNameWithoutExtension(module)}.pdb")
{
// PDB is embedded
@@ -118,11 +120,11 @@ namespace Coverlet.Core.Helpers
{
MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
var matchingResult = MatchDocumentsWithSources(metadataReader);
(bool allDocumentsMatch, string notFoundDocument) = MatchDocumentsWithSources(metadataReader);
if (!matchingResult.allDocumentsMatch)
if (!allDocumentsMatch)
{
firstNotFoundDocument = matchingResult.notFoundDocument;
firstNotFoundDocument = notFoundDocument;
return false;
}
}
@@ -138,16 +140,16 @@ namespace Coverlet.Core.Helpers
public bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
{
firstNotFoundDocument = "";
using (var moduleStream = _fileSystem.OpenRead(module))
using (Stream moduleStream = _fileSystem.OpenRead(module))
using (var peReader = new PEReader(moduleStream))
{
foreach (var entry in peReader.ReadDebugDirectory())
foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
{
if (entry.Type == DebugDirectoryEntryType.CodeView)
{
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
using Stream pdbStream = _fileSystem.OpenRead(_sourceRootTranslator.ResolveFilePath(codeViewData.Path));
using MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
using var metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
MetadataReader metadataReader = null;
try
{
@@ -159,11 +161,11 @@ namespace Coverlet.Core.Helpers
return true;
}
var matchingResult = MatchDocumentsWithSources(metadataReader);
(bool allDocumentsMatch, string notFoundDocument) = MatchDocumentsWithSources(metadataReader);
if (!matchingResult.allDocumentsMatch)
if (!allDocumentsMatch)
{
firstNotFoundDocument = matchingResult.notFoundDocument;
firstNotFoundDocument = notFoundDocument;
return false;
}
}
@@ -196,15 +198,15 @@ namespace Coverlet.Core.Helpers
public void BackupOriginalModule(string module, string identifier)
{
var backupPath = GetBackupPath(module, identifier);
var backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
string backupPath = GetBackupPath(module, identifier);
string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
_fileSystem.Copy(module, backupPath, true);
if (!_backupList.TryAdd(module, backupPath))
{
throw new ArgumentException($"Key already added '{module}'");
}
var symbolFile = Path.ChangeExtension(module, ".pdb");
string symbolFile = Path.ChangeExtension(module, ".pdb");
if (_fileSystem.Exists(symbolFile))
{
_fileSystem.Copy(symbolFile, backupSymbolPath, true);
@@ -217,12 +219,12 @@ namespace Coverlet.Core.Helpers
public virtual void RestoreOriginalModule(string module, string identifier)
{
var backupPath = GetBackupPath(module, identifier);
var backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
string backupPath = GetBackupPath(module, identifier);
string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
// Restore the original module - retry up to 10 times, since the destination file could be locked
// See: https://github.com/tonerdo/coverlet/issues/25
var retryStrategy = CreateRetryStrategy();
Func<TimeSpan> retryStrategy = CreateRetryStrategy();
_retryHelper.Retry(() =>
{
@@ -247,7 +249,7 @@ namespace Coverlet.Core.Helpers
{
// Restore the original module - retry up to 10 times, since the destination file could be locked
// See: https://github.com/tonerdo/coverlet/issues/25
var retryStrategy = CreateRetryStrategy();
Func<TimeSpan> retryStrategy = CreateRetryStrategy();
foreach (string key in _backupList.Keys.ToList())
{
@@ -263,7 +265,7 @@ namespace Coverlet.Core.Helpers
public void DeleteHitsFile(string path)
{
var retryStrategy = CreateRetryStrategy();
Func<TimeSpan> retryStrategy = CreateRetryStrategy();
_retryHelper.Retry(() => _fileSystem.Delete(path), retryStrategy, RetryAttempts);
}
@@ -308,7 +310,7 @@ namespace Coverlet.Core.Helpers
if (module == null)
return false;
foreach (var filter in excludeFilters)
foreach (string filter in excludeFilters)
{
string typePattern = filter.Substring(filter.IndexOf(']') + 1);
@@ -336,7 +338,7 @@ namespace Coverlet.Core.Helpers
if (module == null)
return false;
foreach (var filter in includeFilters)
foreach (string filter in includeFilters)
{
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
@@ -391,7 +393,7 @@ namespace Coverlet.Core.Helpers
Debug.Assert(module != null);
Debug.Assert(filters != null);
foreach (var filter in filters)
foreach (string filter in filters)
{
string typePattern = filter.Substring(filter.IndexOf(']') + 1);
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
+4 -1
View File
@@ -1,7 +1,10 @@
using Coverlet.Core.Abstractions;
// 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.Generic;
using System.Threading;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
{
@@ -1,8 +1,11 @@
using Coverlet.Core.Abstractions;
// 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.Generic;
using System.Diagnostics;
using System.IO;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Helpers
{
@@ -52,7 +55,7 @@ namespace Coverlet.Core.Helpers
throw new ArgumentNullException(nameof(sourceRootMapping));
}
Dictionary<string, List<string>> sourceToDeterministicPathMapping = new Dictionary<string, List<string>>();
var sourceToDeterministicPathMapping = new Dictionary<string, List<string>>();
foreach (KeyValuePair<string, List<SourceRootMapping>> sourceRootMappingEntry in sourceRootMapping)
{
foreach (SourceRootMapping originalPath in sourceRootMappingEntry.Value)
@@ -70,7 +73,7 @@ namespace Coverlet.Core.Helpers
private Dictionary<string, List<SourceRootMapping>> LoadSourceRootMapping(string directory)
{
Dictionary<string, List<SourceRootMapping>> mapping = new Dictionary<string, List<SourceRootMapping>>();
var mapping = new Dictionary<string, List<SourceRootMapping>>();
string mappingFilePath = Path.Combine(directory, MappingFileName);
if (!_fileSystem.Exists(mappingFilePath))
@@ -138,7 +141,7 @@ namespace Coverlet.Core.Helpers
public string ResolveDeterministicPath(string originalFileName)
{
foreach (var originalPath in _sourceToDeterministicPathMapping)
foreach (KeyValuePair<string, List<string>> originalPath in _sourceToDeterministicPathMapping)
{
if (originalFileName.StartsWith(originalPath.Key))
{
@@ -1,8 +1,10 @@
using System;
// 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.Generic;
using System.IO;
using System.Linq;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Exceptions;
using Microsoft.Extensions.DependencyModel;
@@ -167,8 +169,8 @@ namespace Coverlet.Core.Instrumentation
throw new AssemblyResolutionException(name);
}
using DependencyContextJsonReader contextJsonReader = new DependencyContextJsonReader();
Dictionary<string, Lazy<AssemblyDefinition>> libraries = new Dictionary<string, Lazy<AssemblyDefinition>>();
using var contextJsonReader = new DependencyContextJsonReader();
var libraries = new Dictionary<string, Lazy<AssemblyDefinition>>();
foreach (string fileName in Directory.GetFiles(Path.GetDirectoryName(_modulePath), "*.deps.json"))
{
@@ -248,7 +250,7 @@ namespace Coverlet.Core.Instrumentation
continue;
}
foreach (var file in Directory.GetFiles(sharedFrameworkPath))
foreach (string file in Directory.GetFiles(sharedFrameworkPath))
{
if (Path.GetFileName(file).Equals(dllName, StringComparison.OrdinalIgnoreCase))
{
@@ -1,3 +1,6 @@
// 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.Generic;
using System.Diagnostics;
@@ -5,11 +8,10 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Coverlet.Core.Instrumentation.Reachability;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Attributes;
using Coverlet.Core.Helpers;
using Coverlet.Core.Instrumentation.Reachability;
using Coverlet.Core.Symbols;
using Microsoft.Extensions.FileSystemGlobbing;
using Mono.Cecil;
@@ -183,7 +185,7 @@ namespace Coverlet.Core.Instrumentation
// locking issues if we do it while writing.
private void CreateReachabilityHelper()
{
using (var stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.Read))
using (Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.Read))
using (var resolver = new NetstandardAwareAssemblyResolver(_module, _logger))
{
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
@@ -204,7 +206,7 @@ namespace Coverlet.Core.Instrumentation
{
CreateReachabilityHelper();
using (var stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.ReadWrite))
using (Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.ReadWrite))
using (var resolver = new NetstandardAwareAssemblyResolver(_module, _logger))
{
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
@@ -226,11 +228,11 @@ namespace Coverlet.Core.Instrumentation
}
}
var containsAppContext = module.GetType(nameof(System), nameof(AppContext)) != null;
var types = module.GetTypes();
bool containsAppContext = module.GetType(nameof(System), nameof(AppContext)) != null;
IEnumerable<TypeDefinition> types = module.GetTypes();
AddCustomModuleTrackerToModule(module);
var sourceLinkDebugInfo = module.CustomDebugInformations.FirstOrDefault(c => c.Kind == CustomDebugInformationKind.SourceLink);
CustomDebugInformation sourceLinkDebugInfo = module.CustomDebugInformations.FirstOrDefault(c => c.Kind == CustomDebugInformationKind.SourceLink);
if (sourceLinkDebugInfo != null)
{
_result.SourceLink = ((SourceLinkDebugInformation)sourceLinkDebugInfo).Content;
@@ -294,11 +296,11 @@ namespace Coverlet.Core.Instrumentation
customTrackerUnloadModule.Parameters.Add(new ParameterDefinition(eventArgsType));
var appContextType = new TypeReference(nameof(System), nameof(AppContext), module, module.TypeSystem.CoreLibrary);
var onProcessExitMethod = new MethodReference("OnProcessExit", module.TypeSystem.Void, appContextType).Resolve();
var onProcessExitIl = onProcessExitMethod.Body.GetILProcessor();
MethodDefinition onProcessExitMethod = new MethodReference("OnProcessExit", module.TypeSystem.Void, appContextType).Resolve();
ILProcessor onProcessExitIl = onProcessExitMethod.Body.GetILProcessor();
// Put the OnProcessExit body inside try/finally to ensure the call to the UnloadModule.
var lastInst = onProcessExitMethod.Body.Instructions.Last();
Instruction lastInst = onProcessExitMethod.Body.Instructions.Last();
var firstNullParam = Instruction.Create(OpCodes.Ldnull);
var secondNullParam = Instruction.Create(OpCodes.Ldnull);
var callUnload = Instruction.Create(OpCodes.Call, customTrackerUnloadModule);
@@ -307,16 +309,16 @@ namespace Coverlet.Core.Instrumentation
onProcessExitIl.InsertAfter(secondNullParam, callUnload);
var endFinally = Instruction.Create(OpCodes.Endfinally);
onProcessExitIl.InsertAfter(callUnload, endFinally);
var ret = onProcessExitIl.Create(OpCodes.Ret);
var leaveAfterFinally = onProcessExitIl.Create(OpCodes.Leave, ret);
Instruction ret = onProcessExitIl.Create(OpCodes.Ret);
Instruction leaveAfterFinally = onProcessExitIl.Create(OpCodes.Leave, ret);
onProcessExitIl.InsertAfter(endFinally, ret);
foreach (var inst in onProcessExitMethod.Body.Instructions.ToArray())
foreach (Instruction inst in onProcessExitMethod.Body.Instructions.ToArray())
{
// Patch ret to leave after the finally
if (inst.OpCode == OpCodes.Ret && inst != ret)
{
var leaveBodyInstAfterFinally = onProcessExitIl.Create(OpCodes.Leave, ret);
var prevInst = inst.Previous;
Instruction leaveBodyInstAfterFinally = onProcessExitIl.Create(OpCodes.Leave, ret);
Instruction prevInst = inst.Previous;
onProcessExitMethod.Body.Instructions.Remove(inst);
onProcessExitIl.InsertAfter(prevInst, leaveBodyInstAfterFinally);
}
@@ -339,7 +341,7 @@ namespace Coverlet.Core.Instrumentation
private void AddCustomModuleTrackerToModule(ModuleDefinition module)
{
using (AssemblyDefinition coverletInstrumentationAssembly = AssemblyDefinition.ReadAssembly(typeof(ModuleTrackerTemplate).Assembly.Location))
using (var coverletInstrumentationAssembly = AssemblyDefinition.ReadAssembly(typeof(ModuleTrackerTemplate).Assembly.Location))
{
TypeDefinition moduleTrackerTemplate = coverletInstrumentationAssembly.MainModule.GetType(
"Coverlet.Core.Instrumentation", nameof(ModuleTrackerTemplate));
@@ -367,14 +369,14 @@ namespace Coverlet.Core.Instrumentation
foreach (MethodDefinition methodDef in moduleTrackerTemplate.Methods)
{
MethodDefinition methodOnCustomType = new MethodDefinition(methodDef.Name, methodDef.Attributes, methodDef.ReturnType);
var methodOnCustomType = new MethodDefinition(methodDef.Name, methodDef.Attributes, methodDef.ReturnType);
foreach (var parameter in methodDef.Parameters)
foreach (ParameterDefinition parameter in methodDef.Parameters)
{
methodOnCustomType.Parameters.Add(new ParameterDefinition(module.ImportReference(parameter.ParameterType)));
}
foreach (var variable in methodDef.Body.Variables)
foreach (VariableDefinition variable in methodDef.Body.Variables)
{
methodOnCustomType.Body.Variables.Add(new VariableDefinition(module.ImportReference(variable.VariableType)));
}
@@ -398,7 +400,7 @@ namespace Coverlet.Core.Instrumentation
{
// Move to the custom type
var updatedMethodReference = new MethodReference(methodReference.Name, methodReference.ReturnType, _customTrackerTypeDef);
foreach (var parameter in methodReference.Parameters)
foreach (ParameterDefinition parameter in methodReference.Parameters)
updatedMethodReference.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, module.ImportReference(parameter.ParameterType)));
instr.Operand = updatedMethodReference;
@@ -416,7 +418,7 @@ namespace Coverlet.Core.Instrumentation
ilProcessor.Append(instr);
}
foreach (var handler in methodDef.Body.ExceptionHandlers)
foreach (ExceptionHandler handler in methodDef.Body.ExceptionHandlers)
{
if (handler.CatchType != null)
{
@@ -469,12 +471,12 @@ namespace Coverlet.Core.Instrumentation
private void InstrumentType(TypeDefinition type)
{
var methods = type.GetMethods();
IEnumerable<MethodDefinition> methods = type.GetMethods();
// We keep ordinal index because it's the way used by compiler for generated types/methods to
// avoid ambiguity
int ordinal = -1;
foreach (var method in methods)
foreach (MethodDefinition method in methods)
{
MethodDefinition actualMethod = method;
IEnumerable<CustomAttribute> customAttributes = method.CustomAttributes;
@@ -516,8 +518,8 @@ namespace Coverlet.Core.Instrumentation
}
}
var ctors = type.GetConstructors();
foreach (var ctor in ctors)
IEnumerable<MethodDefinition> ctors = type.GetConstructors();
foreach (MethodDefinition ctor in ctors)
{
if (!ctor.CustomAttributes.Any(IsExcludeAttribute))
{
@@ -528,7 +530,7 @@ namespace Coverlet.Core.Instrumentation
private void InstrumentMethod(MethodDefinition method)
{
var sourceFile = method.DebugInformation.SequencePoints.Select(s => _sourceRootTranslator.ResolveFilePath(s.Document.Url)).FirstOrDefault();
string sourceFile = method.DebugInformation.SequencePoints.Select(s => _sourceRootTranslator.ResolveFilePath(s.Document.Url)).FirstOrDefault();
if (!string.IsNullOrEmpty(sourceFile) && _excludedFilesHelper.Exclude(sourceFile))
{
if (!(_excludedSourceFiles ??= new List<string>()).Contains(sourceFile))
@@ -538,7 +540,7 @@ namespace Coverlet.Core.Instrumentation
return;
}
var methodBody = GetMethodBody(method);
MethodBody methodBody = GetMethodBody(method);
if (methodBody == null)
return;
@@ -563,29 +565,29 @@ namespace Coverlet.Core.Instrumentation
{
method.Body.SimplifyMacros();
ILProcessor processor = method.Body.GetILProcessor();
var index = 0;
var count = processor.Body.Instructions.Count;
var branchPoints = _cecilSymbolHelper.GetBranchPoints(method);
var unreachableRanges = _reachabilityHelper.FindUnreachableIL(processor.Body.Instructions, processor.Body.ExceptionHandlers);
var currentUnreachableRangeIx = 0;
int index = 0;
int count = processor.Body.Instructions.Count;
IReadOnlyList<BranchPoint> branchPoints = _cecilSymbolHelper.GetBranchPoints(method);
System.Collections.Immutable.ImmutableArray<ReachabilityHelper.UnreachableRange> unreachableRanges = _reachabilityHelper.FindUnreachableIL(processor.Body.Instructions, processor.Body.ExceptionHandlers);
int currentUnreachableRangeIx = 0;
for (int n = 0; n < count; n++)
{
var currentInstruction = processor.Body.Instructions[index];
var sequencePoint = method.DebugInformation.GetSequencePoint(currentInstruction);
var targetedBranchPoints = branchPoints.Where(p => p.EndOffset == currentInstruction.Offset);
Instruction currentInstruction = processor.Body.Instructions[index];
SequencePoint sequencePoint = method.DebugInformation.GetSequencePoint(currentInstruction);
IEnumerable<BranchPoint> targetedBranchPoints = branchPoints.Where(p => p.EndOffset == currentInstruction.Offset);
// make sure we're looking at the correct unreachable range (if any)
var instrOffset = currentInstruction.Offset;
int instrOffset = currentInstruction.Offset;
while (currentUnreachableRangeIx < unreachableRanges.Length && instrOffset > unreachableRanges[currentUnreachableRangeIx].EndOffset)
{
currentUnreachableRangeIx++;
}
// determine if the unreachable
var isUnreachable = false;
bool isUnreachable = false;
if (currentUnreachableRangeIx < unreachableRanges.Length)
{
var range = unreachableRanges[currentUnreachableRangeIx];
ReachabilityHelper.UnreachableRange range = unreachableRanges[currentUnreachableRangeIx];
isUnreachable = instrOffset >= range.StartOffset && instrOffset <= range.EndOffset;
}
@@ -604,8 +606,8 @@ namespace Coverlet.Core.Instrumentation
continue;
}
var firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, sequencePoint);
foreach (var bodyInstruction in processor.Body.Instructions)
Instruction firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, sequencePoint);
foreach (Instruction bodyInstruction in processor.Body.Instructions)
ReplaceInstructionTarget(bodyInstruction, currentInstruction, firstInjectedInstrumentedOpCode);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
@@ -614,7 +616,7 @@ namespace Coverlet.Core.Instrumentation
index += 2;
}
foreach (var branchTarget in targetedBranchPoints)
foreach (BranchPoint branchTarget in targetedBranchPoints)
{
/*
* Skip branches with no sequence point reference for now.
@@ -625,8 +627,8 @@ namespace Coverlet.Core.Instrumentation
if (branchTarget.StartLine == -1 || branchTarget.Document == null)
continue;
var firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, branchTarget);
foreach (var bodyInstruction in processor.Body.Instructions)
Instruction firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, branchTarget);
foreach (Instruction bodyInstruction in processor.Body.Instructions)
ReplaceInstructionTarget(bodyInstruction, currentInstruction, firstInjectedInstrumentedOpCode);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
@@ -643,7 +645,7 @@ namespace Coverlet.Core.Instrumentation
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
{
if (!_result.Documents.TryGetValue(_sourceRootTranslator.ResolveFilePath(sequencePoint.Document.Url), out var document))
if (!_result.Documents.TryGetValue(_sourceRootTranslator.ResolveFilePath(sequencePoint.Document.Url), out Document document))
{
document = new Document { Path = _sourceRootTranslator.ResolveFilePath(sequencePoint.Document.Url) };
document.Index = _result.Documents.Count;
@@ -663,14 +665,14 @@ namespace Coverlet.Core.Instrumentation
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint)
{
if (!_result.Documents.TryGetValue(_sourceRootTranslator.ResolveFilePath(branchPoint.Document), out var document))
if (!_result.Documents.TryGetValue(_sourceRootTranslator.ResolveFilePath(branchPoint.Document), out Document document))
{
document = new Document { Path = _sourceRootTranslator.ResolveFilePath(branchPoint.Document) };
document.Index = _result.Documents.Count;
_result.Documents.Add(document.Path, document);
}
BranchKey key = new BranchKey(branchPoint.StartLine, (int)branchPoint.Ordinal);
var key = new BranchKey(branchPoint.StartLine, (int)branchPoint.Ordinal);
if (!document.Branches.ContainsKey(key))
{
document.Branches.Add(
@@ -815,7 +817,7 @@ namespace Coverlet.Core.Instrumentation
}
// Check methods members and compiler generated types
foreach (var excludedMethods in _excludedMethods)
foreach ((MethodDefinition, int) excludedMethods in _excludedMethods)
{
// Exclude this member if declaring type is the same of the excluded method and
// the name is synthesized from the name of the excluded method.
@@ -868,34 +870,34 @@ namespace Coverlet.Core.Instrumentation
public CoreLibMetadataImporter(ModuleDefinition module)
{
this.module = module;
this.defaultMetadataImporter = new DefaultMetadataImporter(module);
defaultMetadataImporter = new DefaultMetadataImporter(module);
}
public AssemblyNameReference ImportReference(AssemblyNameReference reference)
{
return this.defaultMetadataImporter.ImportReference(reference);
return defaultMetadataImporter.ImportReference(reference);
}
public TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
{
var importedRef = this.defaultMetadataImporter.ImportReference(type, context);
TypeReference importedRef = defaultMetadataImporter.ImportReference(type, context);
importedRef.GetElementType().Scope = module.TypeSystem.CoreLibrary;
return importedRef;
}
public FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
{
var importedRef = this.defaultMetadataImporter.ImportReference(field, context);
FieldReference importedRef = defaultMetadataImporter.ImportReference(field, context);
importedRef.FieldType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
return importedRef;
}
public MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
{
var importedRef = this.defaultMetadataImporter.ImportReference(method, context);
MethodReference importedRef = defaultMetadataImporter.ImportReference(method, context);
importedRef.DeclaringType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
foreach (var parameter in importedRef.Parameters)
foreach (ParameterDefinition parameter in importedRef.Parameters)
{
if (parameter.ParameterType.Scope == module.TypeSystem.CoreLibrary)
{
@@ -919,14 +921,14 @@ namespace Coverlet.Core.Instrumentation
// Exclude files helper https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.filesystemglobbing.matcher?view=aspnetcore-2.2
internal class ExcludedFilesHelper
{
Matcher _matcher;
readonly Matcher _matcher;
public ExcludedFilesHelper(string[] excludes, ILogger logger)
{
if (excludes != null && excludes.Length > 0)
{
_matcher = new Matcher();
foreach (var excludeRule in excludes)
foreach (string excludeRule in excludes)
{
if (excludeRule is null)
{
@@ -1,3 +1,6 @@
// 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.Generic;
using System.Diagnostics;
@@ -47,11 +50,11 @@ namespace Coverlet.Core.Instrumentation
public override bool Equals(object obj) => Equals(obj);
public bool Equals(BranchKey other) => other is BranchKey branchKey && branchKey.Line == this.Line && branchKey.Ordinal == this.Ordinal;
public bool Equals(BranchKey other) => other is BranchKey branchKey && branchKey.Line == Line && branchKey.Ordinal == Ordinal;
public override int GetHashCode()
{
return (this.Line, this.Ordinal).GetHashCode();
return (Line, Ordinal).GetHashCode();
}
}
@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
// 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.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
@@ -25,7 +27,7 @@ namespace Coverlet.Core.Instrumentation
public static bool SingleHit;
public static bool FlushHitFile;
private static readonly bool _enableLog = int.TryParse(Environment.GetEnvironmentVariable("COVERLET_ENABLETRACKERLOG"), out int result) ? result == 1 : false;
private static string _sessionId = Guid.NewGuid().ToString();
private static readonly string _sessionId = Guid.NewGuid().ToString();
static ModuleTrackerTemplate()
{
@@ -171,8 +173,8 @@ namespace Coverlet.Core.Instrumentation
{
if (_enableLog)
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
DirectoryInfo location = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(currentAssembly.Location), "TrackersHitsLog"));
var currentAssembly = Assembly.GetExecutingAssembly();
var location = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(currentAssembly.Location), "TrackersHitsLog"));
location.Create();
string logFile = Path.Combine(location.FullName, $"{Path.GetFileName(currentAssembly.Location)}_{DateTime.UtcNow.Ticks}_{_sessionId}.txt");
using (var fs = new FileStream(HitsFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
@@ -1,10 +1,13 @@
using Coverlet.Core.Abstractions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
// 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.Immutable;
using System.Linq;
using Coverlet.Core.Abstractions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
namespace Coverlet.Core.Instrumentation.Reachability
{
@@ -252,11 +255,11 @@ namespace Coverlet.Core.Instrumentation.Reachability
return new ReachabilityHelper(ImmutableHashSet<MetadataToken>.Empty);
}
var processedMethods = ImmutableHashSet<MetadataToken>.Empty;
var doNotReturn = ImmutableHashSet.CreateBuilder<MetadataToken>();
foreach (var type in module.Types)
ImmutableHashSet<MetadataToken> processedMethods = ImmutableHashSet<MetadataToken>.Empty;
ImmutableHashSet<MetadataToken>.Builder doNotReturn = ImmutableHashSet.CreateBuilder<MetadataToken>();
foreach (TypeDefinition type in module.Types)
{
foreach (var mtd in type.Methods)
foreach (MethodDefinition mtd in type.Methods)
{
if (mtd.IsNative)
{
@@ -278,14 +281,14 @@ namespace Coverlet.Core.Instrumentation.Reachability
continue;
}
foreach (var instr in body.Instructions)
foreach (Instruction instr in body.Instructions)
{
if (!IsCall(instr, out var calledMtd))
if (!IsCall(instr, out MethodReference calledMtd))
{
continue;
}
var token = calledMtd.MetadataToken;
MetadataToken token = calledMtd.MetadataToken;
if (processedMethods.Contains(token))
{
continue;
@@ -314,8 +317,8 @@ namespace Coverlet.Core.Instrumentation.Reachability
continue;
}
var hasDoesNotReturnAttribute = false;
foreach (var attr in mtdDef.CustomAttributes)
bool hasDoesNotReturnAttribute = false;
foreach (CustomAttribute attr in mtdDef.CustomAttributes)
{
if (Array.IndexOf(doesNotReturnAttributes, attr.AttributeType.Name) != -1)
{
@@ -333,7 +336,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
}
}
var doNoReturnTokens = doNotReturn.ToImmutable();
ImmutableHashSet<MetadataToken> doNoReturnTokens = doNotReturn.ToImmutable();
return new ReachabilityHelper(doNoReturnTokens);
}
@@ -374,7 +377,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
return ImmutableArray<UnreachableRange>.Empty;
}
var (mayContainUnreachableCode, branches) = AnalyzeInstructions(instrs, exceptionHandlers);
(bool mayContainUnreachableCode, ImmutableArray<BranchInstruction> branches) = AnalyzeInstructions(instrs, exceptionHandlers);
// no need to do any more work, nothing unreachable here
if (!mayContainUnreachableCode)
@@ -382,9 +385,9 @@ namespace Coverlet.Core.Instrumentation.Reachability
return ImmutableArray<UnreachableRange>.Empty;
}
var lastInstr = instrs[instrs.Count - 1];
Instruction lastInstr = instrs[instrs.Count - 1];
var blocks = CreateBasicBlocks(instrs, exceptionHandlers, branches);
ImmutableArray<BasicBlock> blocks = CreateBasicBlocks(instrs, exceptionHandlers, branches);
DetermineHeadReachability(blocks);
return DetermineUnreachableRanges(blocks, lastInstr.Offset);
@@ -396,16 +399,16 @@ namespace Coverlet.Core.Instrumentation.Reachability
/// </summary>
private (bool MayContainUnreachableCode, ImmutableArray<BranchInstruction> Branches) AnalyzeInstructions(Collection<Instruction> instrs, Collection<ExceptionHandler> exceptionHandlers)
{
var containsDoesNotReturnCall = false;
bool containsDoesNotReturnCall = false;
var ret = ImmutableArray.CreateBuilder<BranchInstruction>();
foreach (var i in instrs)
ImmutableArray<BranchInstruction>.Builder ret = ImmutableArray.CreateBuilder<BranchInstruction>();
foreach (Instruction i in instrs)
{
containsDoesNotReturnCall = containsDoesNotReturnCall || DoesNotReturn(i);
if (BRANCH_OPCODES.Contains(i.OpCode))
{
var (singleTargetOffset, multiTargetOffsets) = GetInstructionTargets(i, exceptionHandlers);
(int? singleTargetOffset, ImmutableArray<int> multiTargetOffsets) = GetInstructionTargets(i, exceptionHandlers);
if (singleTargetOffset != null)
{
@@ -435,7 +438,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
singleTargetOffset = null;
multiTargetOffsets = ImmutableArray.Create(i.Next.Offset);
foreach (var instr in multiTarget)
foreach (Instruction instr in multiTarget)
{
// in practice these are small arrays, so a scan should be fine
if (multiTargetOffsets.Contains(instr.Offset))
@@ -467,15 +470,15 @@ namespace Coverlet.Core.Instrumentation.Reachability
// flow is allowed so we can scan backwards to see find the block
ExceptionHandler filterForHandler = null;
foreach (var handler in exceptionHandlers)
foreach (ExceptionHandler handler in exceptionHandlers)
{
if (handler.FilterStart == null)
{
continue;
}
var startsAt = handler.FilterStart;
var cur = startsAt;
Instruction startsAt = handler.FilterStart;
Instruction cur = startsAt;
while (cur != null && cur.Offset < i.Offset)
{
cur = cur.Next;
@@ -526,13 +529,13 @@ namespace Coverlet.Core.Instrumentation.Reachability
/// </summary>
private ImmutableArray<UnreachableRange> DetermineUnreachableRanges(ImmutableArray<BasicBlock> blocks, int lastInstructionOffset)
{
var ret = ImmutableArray.CreateBuilder<UnreachableRange>();
ImmutableArray<UnreachableRange>.Builder ret = ImmutableArray.CreateBuilder<UnreachableRange>();
var endOfMethodOffset = lastInstructionOffset + 1; // add 1 so we point _past_ the end of the method
int endOfMethodOffset = lastInstructionOffset + 1; // add 1 so we point _past_ the end of the method
for (var curBlockIx = 0; curBlockIx < blocks.Length; curBlockIx++)
for (int curBlockIx = 0; curBlockIx < blocks.Length; curBlockIx++)
{
var curBlock = blocks[curBlockIx];
BasicBlock curBlock = blocks[curBlockIx];
int endOfCurBlockOffset;
if (curBlockIx == blocks.Length - 1)
@@ -553,11 +556,11 @@ namespace Coverlet.Core.Instrumentation.Reachability
}
// tail isn't reachable, which means there's a call to something that doesn't return...
var doesNotReturnInstr = curBlock.UnreachableAfter;
Instruction doesNotReturnInstr = curBlock.UnreachableAfter;
// and it's everything _after_ the following instruction that is unreachable
// so record the following instruction through the end of the block
var followingInstr = doesNotReturnInstr.Next;
Instruction followingInstr = doesNotReturnInstr.Next;
ret.Add(new UnreachableRange(followingInstr.Offset, endOfCurBlockOffset));
}
@@ -581,13 +584,13 @@ namespace Coverlet.Core.Instrumentation.Reachability
{
var blockLookup = blocks.ToImmutableDictionary(b => b.StartOffset);
var headBlock = blockLookup[0];
BasicBlock headBlock = blockLookup[0];
var knownLive = ImmutableStack.Create(headBlock);
while (!knownLive.IsEmpty)
{
knownLive = knownLive.Pop(out var block);
knownLive = knownLive.Pop(out BasicBlock block);
if (block.HeadReachable)
{
@@ -601,18 +604,18 @@ namespace Coverlet.Core.Instrumentation.Reachability
if (block.TailReachable)
{
// we can reach all the blocks it might flow to
foreach (var reachableOffset in block.BranchesTo)
foreach (int reachableOffset in block.BranchesTo)
{
var reachableBlock = blockLookup[reachableOffset];
BasicBlock reachableBlock = blockLookup[reachableOffset];
knownLive = knownLive.Push(reachableBlock);
}
}
// if the block is covered by an exception handler, then executing _any_ instruction in it
// could conceivably cause those handlers to be visited
foreach (var exceptionHandlerOffset in block.ExceptionBranchesTo)
foreach (int exceptionHandlerOffset in block.ExceptionBranchesTo)
{
var reachableHandler = blockLookup[exceptionHandlerOffset];
BasicBlock reachableHandler = blockLookup[exceptionHandlerOffset];
knownLive = knownLive.Push(reachableHandler);
}
}
@@ -629,16 +632,16 @@ namespace Coverlet.Core.Instrumentation.Reachability
private ImmutableArray<BasicBlock> CreateBasicBlocks(Collection<Instruction> instrs, Collection<ExceptionHandler> exceptionHandlers, ImmutableArray<BranchInstruction> branches)
{
// every branch-like instruction starts or stops a block
var branchInstrLocs = branches.ToLookup(i => i.Offset);
ILookup<int, BranchInstruction> branchInstrLocs = branches.ToLookup(i => i.Offset);
var branchInstrOffsets = branchInstrLocs.Select(k => k.Key).ToImmutableHashSet();
// every target that might be branched to starts or stops a block
var branchTargetOffsetsBuilder = ImmutableHashSet.CreateBuilder<int>();
foreach (var branch in branches)
ImmutableHashSet<int>.Builder branchTargetOffsetsBuilder = ImmutableHashSet.CreateBuilder<int>();
foreach (BranchInstruction branch in branches)
{
if (branch.HasMultiTargets)
{
foreach (var target in branch.TargetOffsets)
foreach (int target in branch.TargetOffsets)
{
branchTargetOffsetsBuilder.Add(target);
}
@@ -651,7 +654,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
// every exception handler an entry point
// either it's handler, or it's filter (if present)
foreach (var handler in exceptionHandlers)
foreach (ExceptionHandler handler in exceptionHandlers)
{
if (handler.FilterStart != null)
{
@@ -663,18 +666,18 @@ namespace Coverlet.Core.Instrumentation.Reachability
}
}
var branchTargetOffsets = branchTargetOffsetsBuilder.ToImmutable();
ImmutableHashSet<int> branchTargetOffsets = branchTargetOffsetsBuilder.ToImmutable();
// ending the method is also important
var endOfMethodOffset = instrs[instrs.Count - 1].Offset;
int endOfMethodOffset = instrs[instrs.Count - 1].Offset;
var blocks = ImmutableArray<BasicBlock>.Empty;
ImmutableArray<BasicBlock> blocks = ImmutableArray<BasicBlock>.Empty;
int? blockStartedAt = null;
Instruction unreachableAfter = null;
foreach (var i in instrs)
foreach (Instruction i in instrs)
{
var offset = i.Offset;
var branchesAtLoc = branchInstrLocs[offset];
int offset = i.Offset;
System.Collections.Generic.IEnumerable<BranchInstruction> branchesAtLoc = branchInstrLocs[offset];
if (blockStartedAt == null)
{
@@ -682,19 +685,19 @@ namespace Coverlet.Core.Instrumentation.Reachability
unreachableAfter = null;
}
var isBranch = branchInstrOffsets.Contains(offset);
var isFollowedByBranchTarget = i.Next != null && branchTargetOffsets.Contains(i.Next.Offset);
var isEndOfMtd = endOfMethodOffset == offset;
bool isBranch = branchInstrOffsets.Contains(offset);
bool isFollowedByBranchTarget = i.Next != null && branchTargetOffsets.Contains(i.Next.Offset);
bool isEndOfMtd = endOfMethodOffset == offset;
if (unreachableAfter == null && DoesNotReturn(i))
{
unreachableAfter = i;
}
var blockEnds = isBranch || isFollowedByBranchTarget || isEndOfMtd;
bool blockEnds = isBranch || isFollowedByBranchTarget || isEndOfMtd;
if (blockEnds)
{
var nextInstr = i.Next;
Instruction nextInstr = i.Next;
// figure out all the different places the basic block could lead to
ImmutableArray<int> goesTo;
@@ -702,7 +705,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
{
// it ends in a branch, where all does it branch?
goesTo = ImmutableArray<int>.Empty;
foreach (var branch in branchesAtLoc)
foreach (BranchInstruction branch in branchesAtLoc)
{
if (branch.HasMultiTargets)
{
@@ -725,30 +728,30 @@ namespace Coverlet.Core.Instrumentation.Reachability
goesTo = ImmutableArray<int>.Empty;
}
var exceptionSwitchesTo = ImmutableArray<int>.Empty;
ImmutableArray<int> exceptionSwitchesTo = ImmutableArray<int>.Empty;
// if the block is covered by any exception handlers then
// it is possible that it will branch to its handler block
foreach (var handler in exceptionHandlers)
foreach (ExceptionHandler handler in exceptionHandlers)
{
var tryStart = handler.TryStart.Offset;
var tryEnd = handler.TryEnd.Offset;
int tryStart = handler.TryStart.Offset;
int tryEnd = handler.TryEnd.Offset;
var containsStartOfTry =
bool containsStartOfTry =
tryStart >= blockStartedAt.Value &&
tryStart <= i.Offset;
var containsEndOfTry =
bool containsEndOfTry =
tryEnd >= blockStartedAt.Value &&
tryEnd <= i.Offset;
var blockInsideTry = blockStartedAt.Value >= tryStart && i.Offset <= tryEnd;
bool blockInsideTry = blockStartedAt.Value >= tryStart && i.Offset <= tryEnd;
// blocks do not necessarily align to the TRY part of exception handlers, so we need to handle three cases:
// - the try _starts_ in the block
// - the try _ends_ in the block
// - the try complete covers the block, but starts and ends before and after it (respectively)
var tryOverlapsBlock = containsStartOfTry || containsEndOfTry || blockInsideTry;
bool tryOverlapsBlock = containsStartOfTry || containsEndOfTry || blockInsideTry;
if (!tryOverlapsBlock)
{
@@ -783,7 +786,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
/// </summary>
private bool DoesNotReturn(Instruction instr)
{
if (!IsCall(instr, out var mtd))
if (!IsCall(instr, out MethodReference mtd))
{
return false;
}
@@ -798,7 +801,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
/// </summary>
private static bool IsCall(Instruction instr, out MethodReference mtd)
{
var opcode = instr.OpCode;
OpCode opcode = instr.OpCode;
if (opcode != OpCodes.Call && opcode != OpCodes.Callvirt)
{
mtd = null;
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -1,3 +1,6 @@
// 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.Generic;
using System.Diagnostics;
@@ -21,42 +24,42 @@ namespace Coverlet.Core.Reporters
public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator)
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var lineCoverage = summary.CalculateLineCoverage(result.Modules);
var branchCoverage = summary.CalculateBranchCoverage(result.Modules);
CoverageDetails lineCoverage = summary.CalculateLineCoverage(result.Modules);
CoverageDetails branchCoverage = summary.CalculateBranchCoverage(result.Modules);
XDocument xml = new XDocument();
XElement coverage = new XElement("coverage");
var xml = new XDocument();
var coverage = new XElement("coverage");
coverage.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(result.Modules).Percent / 100).ToString(CultureInfo.InvariantCulture)));
coverage.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(result.Modules).Percent / 100).ToString(CultureInfo.InvariantCulture)));
coverage.Add(new XAttribute("version", "1.9"));
coverage.Add(new XAttribute("timestamp", (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds));
XElement sources = new XElement("sources");
var sources = new XElement("sources");
List<string> absolutePaths = new List<string>();
var absolutePaths = new List<string>();
if (!result.Parameters.DeterministicReport)
{
absolutePaths = GetBasePaths(result.Modules, result.Parameters.UseSourceLink).ToList();
absolutePaths.ForEach(x => sources.Add(new XElement("source", x)));
}
XElement packages = new XElement("packages");
foreach (var module in result.Modules)
var packages = new XElement("packages");
foreach (KeyValuePair<string, Documents> module in result.Modules)
{
XElement package = new XElement("package");
var package = new XElement("package");
package.Add(new XAttribute("name", Path.GetFileNameWithoutExtension(module.Key)));
package.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(module.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
package.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(module.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
package.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(module.Value)));
XElement classes = new XElement("classes");
foreach (var document in module.Value)
var classes = new XElement("classes");
foreach (KeyValuePair<string, Classes> document in module.Value)
{
foreach (var cls in document.Value)
foreach (KeyValuePair<string, Methods> cls in document.Value)
{
XElement @class = new XElement("class");
var @class = new XElement("class");
@class.Add(new XAttribute("name", cls.Key));
string fileName;
if (!result.Parameters.DeterministicReport)
@@ -72,27 +75,27 @@ namespace Coverlet.Core.Reporters
@class.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(cls.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
@class.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(cls.Value)));
XElement classLines = new XElement("lines");
XElement methods = new XElement("methods");
var classLines = new XElement("lines");
var methods = new XElement("methods");
foreach (var meth in cls.Value)
foreach (KeyValuePair<string, Method> meth in cls.Value)
{
// Skip all methods with no lines
if (meth.Value.Lines.Count == 0)
continue;
XElement method = new XElement("method");
var method = new XElement("method");
method.Add(new XAttribute("name", meth.Key.Split(':').Last().Split('(').First()));
method.Add(new XAttribute("signature", "(" + meth.Key.Split(':').Last().Split('(').Last()));
method.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(meth.Value.Lines).Percent / 100).ToString(CultureInfo.InvariantCulture)));
method.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(meth.Value.Branches).Percent / 100).ToString(CultureInfo.InvariantCulture)));
method.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(meth.Value.Branches)));
XElement lines = new XElement("lines");
foreach (var ln in meth.Value.Lines)
var lines = new XElement("lines");
foreach (KeyValuePair<int, int> ln in meth.Value.Lines)
{
bool isBranchPoint = meth.Value.Branches.Any(b => b.Line == ln.Key);
XElement line = new XElement("line");
var line = new XElement("line");
line.Add(new XAttribute("number", ln.Key.ToString()));
line.Add(new XAttribute("hits", ln.Value.ToString()));
line.Add(new XAttribute("branch", isBranchPoint.ToString()));
@@ -100,13 +103,13 @@ namespace Coverlet.Core.Reporters
if (isBranchPoint)
{
var branches = meth.Value.Branches.Where(b => b.Line == ln.Key).ToList();
var branchInfoCoverage = summary.CalculateBranchCoverage(branches);
CoverageDetails branchInfoCoverage = summary.CalculateBranchCoverage(branches);
line.Add(new XAttribute("condition-coverage", $"{branchInfoCoverage.Percent.ToString(CultureInfo.InvariantCulture)}% ({branchInfoCoverage.Covered.ToString(CultureInfo.InvariantCulture)}/{branchInfoCoverage.Total.ToString(CultureInfo.InvariantCulture)})"));
XElement conditions = new XElement("conditions");
var conditions = new XElement("conditions");
var byOffset = branches.GroupBy(b => b.Offset).ToDictionary(b => b.Key, b => b.ToList());
foreach (var entry in byOffset)
foreach (KeyValuePair<int, List<BranchInfo>> entry in byOffset)
{
XElement condition = new XElement("condition");
var condition = new XElement("condition");
condition.Add(new XAttribute("number", entry.Key));
condition.Add(new XAttribute("type", entry.Value.Count() > 2 ? "switch" : "jump")); // Just guessing here
condition.Add(new XAttribute("coverage", $"{summary.CalculateBranchCoverage(entry.Value).Percent.ToString(CultureInfo.InvariantCulture)}%"));
@@ -218,7 +221,7 @@ namespace Coverlet.Core.Reporters
return path;
}
foreach (var basePath in basePaths)
foreach (string basePath in basePaths)
{
if (path.StartsWith(basePath))
{
+3 -2
View File
@@ -1,7 +1,8 @@
using Newtonsoft.Json;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Coverlet.Core.Abstractions;
using System;
using Newtonsoft.Json;
namespace Coverlet.Core.Reporters
{
+16 -14
View File
@@ -1,7 +1,9 @@
using System;
using System.Linq;
using System.Collections.Generic;
// 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.Generic;
using System.Linq;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Reporters
@@ -21,21 +23,21 @@ namespace Coverlet.Core.Reporters
throw new NotSupportedException("Deterministic report not supported by lcov reporter");
}
CoverageSummary summary = new CoverageSummary();
List<string> lcov = new List<string>();
var summary = new CoverageSummary();
var lcov = new List<string>();
foreach (var module in result.Modules)
foreach (KeyValuePair<string, Documents> module in result.Modules)
{
foreach (var doc in module.Value)
foreach (KeyValuePair<string, Classes> doc in module.Value)
{
var docLineCoverage = summary.CalculateLineCoverage(doc.Value);
var docBranchCoverage = summary.CalculateBranchCoverage(doc.Value);
var docMethodCoverage = summary.CalculateMethodCoverage(doc.Value);
CoverageDetails docLineCoverage = summary.CalculateLineCoverage(doc.Value);
CoverageDetails docBranchCoverage = summary.CalculateBranchCoverage(doc.Value);
CoverageDetails docMethodCoverage = summary.CalculateMethodCoverage(doc.Value);
lcov.Add("SF:" + doc.Key);
foreach (var @class in doc.Value)
foreach (KeyValuePair<string, Methods> @class in doc.Value)
{
foreach (var method in @class.Value)
foreach (KeyValuePair<string, Method> method in @class.Value)
{
// Skip all methods with no lines
if (method.Value.Lines.Count == 0)
@@ -44,10 +46,10 @@ namespace Coverlet.Core.Reporters
lcov.Add($"FN:{method.Value.Lines.First().Key - 1},{method.Key}");
lcov.Add($"FNDA:{method.Value.Lines.First().Value},{method.Key}");
foreach (var line in method.Value.Lines)
foreach (KeyValuePair<int, int> line in method.Value.Lines)
lcov.Add($"DA:{line.Key},{line.Value}");
foreach (var branch in method.Value.Branches)
foreach (BranchInfo branch in method.Value.Branches)
{
lcov.Add($"BRDA:{branch.Line},{branch.Offset},{branch.Path},{branch.Hits}");
}
@@ -1,10 +1,12 @@
// 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.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Reporters
@@ -24,63 +26,63 @@ namespace Coverlet.Core.Reporters
throw new NotSupportedException("Deterministic report not supported by openCover reporter");
}
CoverageSummary summary = new CoverageSummary();
XDocument xml = new XDocument();
XElement coverage = new XElement("CoverageSession");
XElement coverageSummary = new XElement("Summary");
XElement modules = new XElement("Modules");
var summary = new CoverageSummary();
var xml = new XDocument();
var coverage = new XElement("CoverageSession");
var coverageSummary = new XElement("Summary");
var modules = new XElement("Modules");
int numClasses = 0, numMethods = 0;
int visitedClasses = 0, visitedMethods = 0;
int i = 1;
foreach (var mod in result.Modules)
foreach (System.Collections.Generic.KeyValuePair<string, Documents> mod in result.Modules)
{
XElement module = new XElement("Module");
var module = new XElement("Module");
module.Add(new XAttribute("hash", Guid.NewGuid().ToString().ToUpper()));
XElement path = new XElement("ModulePath", mod.Key);
XElement time = new XElement("ModuleTime", DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss"));
XElement name = new XElement("ModuleName", Path.GetFileNameWithoutExtension(mod.Key));
var path = new XElement("ModulePath", mod.Key);
var time = new XElement("ModuleTime", DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss"));
var name = new XElement("ModuleName", Path.GetFileNameWithoutExtension(mod.Key));
module.Add(path);
module.Add(time);
module.Add(name);
XElement files = new XElement("Files");
XElement classes = new XElement("Classes");
var files = new XElement("Files");
var classes = new XElement("Classes");
foreach (var doc in mod.Value)
foreach (System.Collections.Generic.KeyValuePair<string, Classes> doc in mod.Value)
{
XElement file = new XElement("File");
var file = new XElement("File");
file.Add(new XAttribute("uid", i.ToString()));
file.Add(new XAttribute("fullPath", doc.Key));
files.Add(file);
foreach (var cls in doc.Value)
foreach (System.Collections.Generic.KeyValuePair<string, Methods> cls in doc.Value)
{
XElement @class = new XElement("Class");
XElement classSummary = new XElement("Summary");
var @class = new XElement("Class");
var classSummary = new XElement("Summary");
XElement className = new XElement("FullName", cls.Key);
var className = new XElement("FullName", cls.Key);
XElement methods = new XElement("Methods");
var methods = new XElement("Methods");
int j = 0;
var classVisited = false;
bool classVisited = false;
foreach (var meth in cls.Value)
foreach (System.Collections.Generic.KeyValuePair<string, Method> meth in cls.Value)
{
// Skip all methods with no lines
if (meth.Value.Lines.Count == 0)
continue;
var methLineCoverage = summary.CalculateLineCoverage(meth.Value.Lines);
var methBranchCoverage = summary.CalculateBranchCoverage(meth.Value.Branches);
var methCyclomaticComplexity = summary.CalculateCyclomaticComplexity(meth.Value.Branches);
var methNpathComplexity = summary.CalculateNpathComplexity(meth.Value.Branches);
CoverageDetails methLineCoverage = summary.CalculateLineCoverage(meth.Value.Lines);
CoverageDetails methBranchCoverage = summary.CalculateBranchCoverage(meth.Value.Branches);
int methCyclomaticComplexity = summary.CalculateCyclomaticComplexity(meth.Value.Branches);
int methNpathComplexity = summary.CalculateNpathComplexity(meth.Value.Branches);
XElement method = new XElement("Method");
var method = new XElement("Method");
method.Add(new XAttribute("cyclomaticComplexity", methCyclomaticComplexity.ToString()));
method.Add(new XAttribute("nPathComplexity", methCyclomaticComplexity.ToString()));
@@ -91,12 +93,12 @@ namespace Coverlet.Core.Reporters
method.Add(new XAttribute("isSetter", meth.Key.Contains("set_").ToString()));
method.Add(new XAttribute("isStatic", (!meth.Key.Contains("get_") || !meth.Key.Contains("set_")).ToString()));
XElement methodName = new XElement("Name", meth.Key);
var methodName = new XElement("Name", meth.Key);
XElement fileRef = new XElement("FileRef");
var fileRef = new XElement("FileRef");
fileRef.Add(new XAttribute("uid", i.ToString()));
XElement methodPoint = new XElement("MethodPoint");
var methodPoint = new XElement("MethodPoint");
methodPoint.Add(new XAttribute("vc", methLineCoverage.Covered.ToString()));
methodPoint.Add(new XAttribute("uspid", "0"));
methodPoint.Add(new XAttribute(XName.Get("type", "xsi"), "SequencePoint"));
@@ -111,19 +113,19 @@ namespace Coverlet.Core.Reporters
methodPoint.Add(new XAttribute("fileid", i.ToString()));
// They're really just lines
XElement sequencePoints = new XElement("SequencePoints");
XElement branchPoints = new XElement("BranchPoints");
XElement methodSummary = new XElement("Summary");
var sequencePoints = new XElement("SequencePoints");
var branchPoints = new XElement("BranchPoints");
var methodSummary = new XElement("Summary");
int k = 0;
int kBr = 0;
var methodVisited = false;
bool methodVisited = false;
foreach (var lines in meth.Value.Lines)
foreach (System.Collections.Generic.KeyValuePair<int, int> lines in meth.Value.Lines)
{
var lineBranches = meth.Value.Branches.Where(branchInfo => branchInfo.Line == lines.Key).ToArray();
var branchCoverage = summary.CalculateBranchCoverage(lineBranches);
BranchInfo[] lineBranches = meth.Value.Branches.Where(branchInfo => branchInfo.Line == lines.Key).ToArray();
CoverageDetails branchCoverage = summary.CalculateBranchCoverage(lineBranches);
XElement sequencePoint = new XElement("SequencePoint");
var sequencePoint = new XElement("SequencePoint");
sequencePoint.Add(new XAttribute("vc", lines.Value.ToString()));
sequencePoint.Add(new XAttribute("uspid", lines.Key.ToString()));
sequencePoint.Add(new XAttribute("ordinal", k.ToString()));
@@ -145,9 +147,9 @@ namespace Coverlet.Core.Reporters
k++;
}
foreach (var branche in meth.Value.Branches)
foreach (BranchInfo branche in meth.Value.Branches)
{
XElement branchPoint = new XElement("BranchPoint");
var branchPoint = new XElement("BranchPoint");
branchPoint.Add(new XAttribute("vc", branche.Hits.ToString()));
branchPoint.Add(new XAttribute("uspid", branche.Line.ToString()));
branchPoint.Add(new XAttribute("ordinal", branche.Ordinal.ToString()));
@@ -192,11 +194,11 @@ namespace Coverlet.Core.Reporters
if (classVisited)
visitedClasses++;
var classLineCoverage = summary.CalculateLineCoverage(cls.Value);
var classBranchCoverage = summary.CalculateBranchCoverage(cls.Value);
var classMethodCoverage = summary.CalculateMethodCoverage(cls.Value);
var classMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(cls.Value);
var classMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(cls.Value);
CoverageDetails classLineCoverage = summary.CalculateLineCoverage(cls.Value);
CoverageDetails classBranchCoverage = summary.CalculateBranchCoverage(cls.Value);
CoverageDetails classMethodCoverage = summary.CalculateMethodCoverage(cls.Value);
int classMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(cls.Value);
int classMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(cls.Value);
classSummary.Add(new XAttribute("numSequencePoints", classLineCoverage.Total.ToString()));
classSummary.Add(new XAttribute("visitedSequencePoints", classLineCoverage.Covered.ToString()));
@@ -224,10 +226,10 @@ namespace Coverlet.Core.Reporters
modules.Add(module);
}
var moduleLineCoverage = summary.CalculateLineCoverage(result.Modules);
var moduleBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
var moduleMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(result.Modules);
var moduleMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(result.Modules);
CoverageDetails moduleLineCoverage = summary.CalculateLineCoverage(result.Modules);
CoverageDetails moduleBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
int moduleMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(result.Modules);
int moduleMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(result.Modules);
coverageSummary.Add(new XAttribute("numSequencePoints", moduleLineCoverage.Total.ToString()));
coverageSummary.Add(new XAttribute("visitedSequencePoints", moduleLineCoverage.Covered.ToString()));
@@ -1,14 +1,16 @@
// 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.Linq;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Reporters
{
internal class ReporterFactory
{
private string _format;
private IReporter[] _reporters;
private readonly string _format;
private readonly IReporter[] _reporters;
public ReporterFactory(string format)
{
@@ -1,7 +1,9 @@
using System;
// 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.Globalization;
using System.Text;
using Coverlet.Core.Abstractions;
namespace Coverlet.Core.Reporters
@@ -23,9 +25,9 @@ namespace Coverlet.Core.Reporters
// Calculate coverage
var summary = new CoverageSummary();
var overallLineCoverage = summary.CalculateLineCoverage(result.Modules);
var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);
CoverageDetails overallLineCoverage = summary.CalculateLineCoverage(result.Modules);
CoverageDetails overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
CoverageDetails overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);
// Report coverage
var stringBuilder = new StringBuilder();
+3 -1
View File
@@ -1,6 +1,8 @@
// 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.Diagnostics;
using System.Text.RegularExpressions;
namespace Coverlet.Core.Symbols
{
+31 -34
View File
@@ -1,12 +1,12 @@
//
// This class is based heavily on the work of the OpenCover
// team in OpenCover.Framework.Symbols.CecilSymbolManager
//
// 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.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Extensions;
@@ -399,11 +399,11 @@ namespace Coverlet.Core.Symbols
*/
if (!_compilerGeneratedBranchesToExclude.ContainsKey(methodDefinition.FullName))
{
List<int> detectedBranches = new List<int>();
var detectedBranches = new List<int>();
Collection<ExceptionHandler> handlers = methodDefinition.Body.ExceptionHandlers;
int numberOfCatchBlocks = 1;
foreach (var handler in handlers)
foreach (ExceptionHandler handler in handlers)
{
if (handlers.Any(h => h.HandlerStart == handler.HandlerEnd))
{
@@ -1021,13 +1021,13 @@ namespace Coverlet.Core.Symbols
continue;
}
var pathCounter = 0;
int pathCounter = 0;
// store branch origin offset
var branchOffset = instruction.Offset;
var closestSeqPt = FindClosestInstructionWithSequencePoint(methodDefinition.Body, instruction).Maybe(i => methodDefinition.DebugInformation.GetSequencePoint(i));
var branchingInstructionLine = closestSeqPt.Maybe(x => x.StartLine, -1);
var document = closestSeqPt.Maybe(x => x.Document.Url);
int branchOffset = instruction.Offset;
SequencePoint closestSeqPt = FindClosestInstructionWithSequencePoint(methodDefinition.Body, instruction).Maybe(i => methodDefinition.DebugInformation.GetSequencePoint(i));
int branchingInstructionLine = closestSeqPt.Maybe(x => x.StartLine, -1);
string document = closestSeqPt.Maybe(x => x.Document.Url);
if (instruction.Next == null)
{
@@ -1054,9 +1054,9 @@ namespace Coverlet.Core.Symbols
// Add Default branch (Path=0)
// Follow else/default instruction
var @else = instruction.Next;
Instruction @else = instruction.Next;
var pathOffsetList = GetBranchPath(@else);
List<int> pathOffsetList = GetBranchPath(@else);
// add Path 0
var path0 = new BranchPoint
@@ -1077,8 +1077,7 @@ namespace Coverlet.Core.Symbols
if (instruction.OpCode.Code != Code.Switch)
{
// Follow instruction at operand
var @then = instruction.Operand as Instruction;
if (@then == null)
if (instruction.Operand is not Instruction @then)
return false;
ordinal = BuildPointsForBranch(list, then, branchingInstructionLine, document, branchOffset,
@@ -1086,8 +1085,7 @@ namespace Coverlet.Core.Symbols
}
else // instruction.OpCode.Code == Code.Switch
{
var branchInstructions = instruction.Operand as Instruction[];
if (branchInstructions == null || branchInstructions.Length == 0)
if (instruction.Operand is not Instruction[] branchInstructions || branchInstructions.Length == 0)
return false;
ordinal = BuildPointsForSwitchCases(list, path0, branchInstructions, branchingInstructionLine,
@@ -1099,7 +1097,7 @@ namespace Coverlet.Core.Symbols
private static uint BuildPointsForBranch(List<BranchPoint> list, Instruction then, int branchingInstructionLine, string document,
int branchOffset, uint ordinal, int pathCounter, BranchPoint path0, List<Instruction> instructions, MethodDefinition methodDefinition)
{
var pathOffsetList1 = GetBranchPath(@then);
List<int> pathOffsetList1 = GetBranchPath(@then);
// Add path 1
var path1 = new BranchPoint
@@ -1119,7 +1117,7 @@ namespace Coverlet.Core.Symbols
// only add branch if branch does not match a known sequence
// e.g. auto generated field assignment
// or encapsulates at least one sequence point
var offsets = new[]
int[] offsets = new[]
{
path0.Offset,
path0.EndOffset,
@@ -1127,22 +1125,22 @@ namespace Coverlet.Core.Symbols
path1.EndOffset
};
var ignoreSequences = new[]
Code[][] ignoreSequences = new[]
{
// we may need other samples
new[] {Code.Brtrue_S, Code.Pop, Code.Ldsfld, Code.Ldftn, Code.Newobj, Code.Dup, Code.Stsfld, Code.Newobj}, // CachedAnonymousMethodDelegate field allocation
};
var bs = offsets.Min();
var be = offsets.Max();
int bs = offsets.Min();
int be = offsets.Max();
var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList();
var match = ignoreSequences
bool match = ignoreSequences
.Where(ignoreSequence => range.Count >= ignoreSequence.Length)
.Any(ignoreSequence => range.Zip(ignoreSequence, (instruction, code) => instruction.OpCode.Code == code).All(x => x));
var count = range
int count = range
.Count(i => methodDefinition.DebugInformation.GetSequencePoint(i) != null);
if (!match || count > 0)
@@ -1156,7 +1154,7 @@ namespace Coverlet.Core.Symbols
private static uint BuildPointsForSwitchCases(List<BranchPoint> list, BranchPoint path0, Instruction[] branchInstructions,
int branchingInstructionLine, string document, int branchOffset, uint ordinal, ref int pathCounter)
{
var counter = pathCounter;
int counter = pathCounter;
list.Add(path0);
// Add Conditional Branches (Path>0)
list.AddRange(branchInstructions.Select(GetBranchPath)
@@ -1342,7 +1340,7 @@ namespace Coverlet.Core.Symbols
}
...
*/
var autogeneratedBackingFields = methodDefinition.DeclaringType.Fields.Where(x =>
IEnumerable<FieldDefinition> autogeneratedBackingFields = methodDefinition.DeclaringType.Fields.Where(x =>
x.CustomAttributes.Any(ca => ca.AttributeType.FullName.Equals(typeof(CompilerGeneratedAttribute).FullName)) &&
x.FullName.EndsWith("k__BackingField"));
@@ -1378,7 +1376,7 @@ namespace Coverlet.Core.Symbols
.Where(e => e.HandlerType == ExceptionHandlerType.Filter)
.ToList();
foreach (var exceptionHandler in handlers)
foreach (ExceptionHandler exceptionHandler in handlers)
{
Instruction startFilter = exceptionHandler.FilterStart;
Instruction endFilter = startFilter;
@@ -1418,7 +1416,7 @@ namespace Coverlet.Core.Symbols
private static int GetOffsetOfNextEndfinally(MethodBody body, int startOffset)
{
var lastOffset = body.Instructions.LastOrDefault().Maybe(i => i.Offset, int.MaxValue);
int lastOffset = body.Instructions.LastOrDefault().Maybe(i => i.Offset, int.MaxValue);
return body.Instructions.FirstOrDefault(i => i.Offset >= startOffset && i.OpCode.Code == Code.Endfinally).Maybe(i => i.Offset, lastOffset);
}
@@ -1428,12 +1426,11 @@ namespace Coverlet.Core.Symbols
if (instruction != null)
{
var point = instruction;
Instruction point = instruction;
offsetList.Add(point.Offset);
while (point.OpCode == OpCodes.Br || point.OpCode == OpCodes.Br_S)
{
var nextPoint = point.Operand as Instruction;
if (nextPoint != null)
if (point.Operand is Instruction nextPoint)
{
point = nextPoint;
offsetList.Add(point.Offset);
@@ -1453,12 +1450,12 @@ namespace Coverlet.Core.Symbols
var sequencePointsInMethod = methodBody.Instructions.Where(i => HasValidSequencePoint(i, methodBody.Method)).ToList();
if (!sequencePointsInMethod.Any())
return null;
var idx = sequencePointsInMethod.BinarySearch(instruction, new InstructionByOffsetComparer());
int idx = sequencePointsInMethod.BinarySearch(instruction, new InstructionByOffsetComparer());
Instruction prev;
if (idx < 0)
{
// no exact match, idx corresponds to the next, larger element
var lower = Math.Max(~idx - 1, 0);
int lower = Math.Max(~idx - 1, 0);
prev = sequencePointsInMethod[lower];
}
else
@@ -1472,7 +1469,7 @@ namespace Coverlet.Core.Symbols
private static bool HasValidSequencePoint(Instruction instruction, MethodDefinition methodDefinition)
{
var sp = methodDefinition.DebugInformation.GetSequencePoint(instruction);
SequencePoint sp = methodDefinition.DebugInformation.GetSequencePoint(instruction);
return sp != null && sp.StartLine != StepOverLineCode;
}
+4 -1
View File
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Build.Utilities;
namespace Coverlet.MSbuild.Tasks
@@ -1,3 +1,6 @@
// 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.Generic;
using System.Globalization;
@@ -17,7 +20,7 @@ namespace Coverlet.MSbuild.Tasks
{
public class CoverageResultTask : BaseTask
{
private MSBuildLogger _logger;
private readonly MSBuildLogger _logger;
[Required]
public string Output { get; set; }
@@ -63,11 +66,11 @@ namespace Coverlet.MSbuild.Tasks
Coverage coverage = null;
using (Stream instrumenterStateStream = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open))
{
var instrumentationHelper = ServiceProvider.GetService<IInstrumentationHelper>();
IInstrumentationHelper instrumentationHelper = ServiceProvider.GetService<IInstrumentationHelper>();
// Task.Log is teared down after a task and thus the new MSBuildLogger must be passed to the InstrumentationHelper
// https://github.com/microsoft/msbuild/issues/5153
instrumentationHelper.SetLogger(_logger);
coverage = new Coverage(CoveragePrepareResult.Deserialize(instrumenterStateStream), this._logger, ServiceProvider.GetService<IInstrumentationHelper>(), fileSystem, ServiceProvider.GetService<ISourceRootTranslator>());
coverage = new Coverage(CoveragePrepareResult.Deserialize(instrumenterStateStream), _logger, ServiceProvider.GetService<IInstrumentationHelper>(), fileSystem, ServiceProvider.GetService<ISourceRootTranslator>());
}
try
@@ -82,7 +85,7 @@ namespace Coverlet.MSbuild.Tasks
CoverageResult result = coverage.GetCoverageResult();
var directory = Path.GetDirectoryName(Output);
string directory = Path.GetDirectoryName(Output);
if (directory == string.Empty)
{
directory = Directory.GetCurrentDirectory();
@@ -92,12 +95,12 @@ namespace Coverlet.MSbuild.Tasks
Directory.CreateDirectory(directory);
}
var formats = OutputFormat.Split(',');
string[] formats = OutputFormat.Split(',');
var coverageReportPaths = new List<ITaskItem>(formats.Length);
ISourceRootTranslator sourceRootTranslator = ServiceProvider.GetService<ISourceRootTranslator>();
foreach (var format in formats)
foreach (string format in formats)
{
var reporter = new ReporterFactory(format).CreateReporter();
IReporter reporter = new ReporterFactory(format).CreateReporter();
if (reporter == null)
{
throw new Exception($"Specified output format '{format}' is not supported");
@@ -119,7 +122,7 @@ namespace Coverlet.MSbuild.Tasks
ServiceProvider.GetService<IConsole>(),
result,
sourceRootTranslator);
var path = writer.WriteReport();
string path = writer.WriteReport();
var metadata = new Dictionary<string, string> { ["Format"] = format };
coverageReportPaths.Add(new TaskItem(path, metadata));
}
@@ -129,7 +132,7 @@ namespace Coverlet.MSbuild.Tasks
var thresholdTypeFlagQueue = new Queue<ThresholdTypeFlags>();
foreach (var thresholdType in ThresholdType.Split(',').Select(t => t.Trim()))
foreach (string thresholdType in ThresholdType.Split(',').Select(t => t.Trim()))
{
if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
{
@@ -145,18 +148,18 @@ namespace Coverlet.MSbuild.Tasks
}
}
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>();
if (Threshold.Contains(','))
{
var thresholdValues = Threshold.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
IEnumerable<string> thresholdValues = Threshold.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
if (thresholdValues.Count() != thresholdTypeFlagQueue.Count())
{
throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count()}) and values count ({thresholdValues.Count()}) doesn't match");
}
foreach (var threshold in thresholdValues)
foreach (string threshold in thresholdValues)
{
if (double.TryParse(threshold, out var value))
if (double.TryParse(threshold, out double value))
{
thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
}
@@ -176,7 +179,7 @@ namespace Coverlet.MSbuild.Tasks
}
}
var thresholdStat = ThresholdStatistic.Minimum;
ThresholdStatistic thresholdStat = ThresholdStatistic.Minimum;
if (ThresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
{
thresholdStat = ThresholdStatistic.Average;
@@ -189,23 +192,23 @@ namespace Coverlet.MSbuild.Tasks
var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
var summary = new CoverageSummary();
var linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
CoverageDetails linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
CoverageDetails branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
CoverageDetails methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
var totalLinePercent = linePercentCalculation.Percent;
var totalBranchPercent = branchPercentCalculation.Percent;
var totalMethodPercent = methodPercentCalculation.Percent;
double totalLinePercent = linePercentCalculation.Percent;
double totalBranchPercent = branchPercentCalculation.Percent;
double totalMethodPercent = methodPercentCalculation.Percent;
var averageLinePercent = linePercentCalculation.AverageModulePercent;
var averageBranchPercent = branchPercentCalculation.AverageModulePercent;
var averageMethodPercent = methodPercentCalculation.AverageModulePercent;
double averageLinePercent = linePercentCalculation.AverageModulePercent;
double averageBranchPercent = branchPercentCalculation.AverageModulePercent;
double averageMethodPercent = methodPercentCalculation.AverageModulePercent;
foreach (var module in result.Modules)
foreach (KeyValuePair<string, Documents> module in result.Modules)
{
var linePercent = summary.CalculateLineCoverage(module.Value).Percent;
var branchPercent = summary.CalculateBranchCoverage(module.Value).Percent;
var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent;
double linePercent = summary.CalculateLineCoverage(module.Value).Percent;
double branchPercent = summary.CalculateBranchCoverage(module.Value).Percent;
double methodPercent = summary.CalculateMethodCoverage(module.Value).Percent;
coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
}
@@ -222,7 +225,7 @@ namespace Coverlet.MSbuild.Tasks
Console.WriteLine(coverageTable.ToStringAlternative());
var thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, thresholdStat);
ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, thresholdStat);
if (thresholdTypeFlags != ThresholdTypeFlags.None)
{
var exceptionMessageBuilder = new StringBuilder();
@@ -1,7 +1,9 @@
using System;
// 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.Diagnostics;
using System.IO;
using Coverlet.Core;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
@@ -9,6 +11,7 @@ using Coverlet.Core.Symbols;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Extensions.DependencyInjection;
using ILogger = Coverlet.Core.Abstractions.ILogger;
namespace Coverlet.MSbuild.Tasks
@@ -81,9 +84,9 @@ namespace Coverlet.MSbuild.Tasks
try
{
var fileSystem = ServiceProvider.GetService<IFileSystem>();
IFileSystem fileSystem = ServiceProvider.GetService<IFileSystem>();
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = Include?.Split(','),
IncludeDirectories = IncludeDirectory?.Split(','),
@@ -99,7 +102,7 @@ namespace Coverlet.MSbuild.Tasks
DoesNotReturnAttributes = DoesNotReturnAttribute?.Split(',')
};
Coverage coverage = new Coverage(Path,
var coverage = new Coverage(Path,
parameters,
_logger,
ServiceProvider.GetService<IInstrumentationHelper>(),
@@ -109,7 +112,7 @@ namespace Coverlet.MSbuild.Tasks
CoveragePrepareResult prepareResult = coverage.PrepareModules();
InstrumenterState = new TaskItem(System.IO.Path.GetTempFileName());
using (var instrumentedStateFile = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open, FileAccess.Write))
using (Stream instrumentedStateFile = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open, FileAccess.Write))
{
using (Stream serializedState = CoveragePrepareResult.Serialize(prepareResult))
{
+3 -1
View File
@@ -1,5 +1,7 @@
using System;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using ILogger = Coverlet.Core.Abstractions.ILogger;
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
+3 -2
View File
@@ -1,8 +1,9 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using Coverlet.Core;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Reporters;
namespace Coverlet.MSbuild.Tasks
{
@@ -1,4 +1,7 @@
using System;
// 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.ComponentModel;
using System.IO;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
@@ -14,14 +17,14 @@ namespace Coverlet.Collector.Tests
public class AttachmentManagerTests
{
private AttachmentManager _attachmentManager;
private Mock<DataCollectionSink> _mockDataCollectionSink;
private DataCollectionContext _dataCollectionContext;
private TestPlatformLogger _testPlatformLogger;
private TestPlatformEqtTrace _eqtTrace;
private Mock<IFileHelper> _mockFileHelper;
private Mock<IDirectoryHelper> _mockDirectoryHelper;
private Mock<ICountDownEvent> _mockCountDownEvent;
private Mock<DataCollectionLogger> _mockDataCollectionLogger;
private readonly Mock<DataCollectionSink> _mockDataCollectionSink;
private readonly DataCollectionContext _dataCollectionContext;
private readonly TestPlatformLogger _testPlatformLogger;
private readonly TestPlatformEqtTrace _eqtTrace;
private readonly Mock<IFileHelper> _mockFileHelper;
private readonly Mock<IDirectoryHelper> _mockDirectoryHelper;
private readonly Mock<ICountDownEvent> _mockCountDownEvent;
private readonly Mock<DataCollectionLogger> _mockDataCollectionLogger;
public AttachmentManagerTests()
{
@@ -71,7 +74,7 @@ namespace Coverlet.Collector.Tests
[Fact]
public void SendCoverageReportShouldSendAttachmentToTestPlatform()
{
var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
_attachmentManager = new AttachmentManager(_mockDataCollectionSink.Object, _dataCollectionContext, _testPlatformLogger,
_eqtTrace, directory.ToString(), new FileHelper(), _mockDirectoryHelper.Object, _mockCountDownEvent.Object);
@@ -1,9 +1,11 @@
// 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.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
using Moq;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
@@ -22,15 +24,15 @@ namespace Coverlet.Collector.Tests
{
public class CoverletCoverageDataCollectorTests
{
private DataCollectionEnvironmentContext _context;
private readonly DataCollectionEnvironmentContext _context;
private CoverletCoverageCollector _coverletCoverageDataCollector;
private DataCollectionContext _dataCollectionContext;
private Mock<DataCollectionEvents> _mockDataColectionEvents;
private Mock<DataCollectionSink> _mockDataCollectionSink;
private Mock<ICoverageWrapper> _mockCoverageWrapper;
private Mock<ICountDownEventFactory> _mockCountDownEventFactory;
private readonly DataCollectionContext _dataCollectionContext;
private readonly Mock<DataCollectionEvents> _mockDataColectionEvents;
private readonly Mock<DataCollectionSink> _mockDataCollectionSink;
private readonly Mock<ICoverageWrapper> _mockCoverageWrapper;
private readonly Mock<ICountDownEventFactory> _mockCountDownEventFactory;
private XmlElement _configurationElement;
private Mock<DataCollectionLogger> _mockLogger;
private readonly Mock<DataCollectionLogger> _mockLogger;
public CoverletCoverageDataCollectorTests()
{
@@ -39,7 +41,7 @@ namespace Coverlet.Collector.Tests
_mockLogger = new Mock<DataCollectionLogger>();
_configurationElement = null;
TestCase testcase = new TestCase { Id = Guid.NewGuid() };
var testcase = new TestCase { Id = Guid.NewGuid() };
_dataCollectionContext = new DataCollectionContext(testcase);
_context = new DataCollectionEnvironmentContext(_dataCollectionContext);
_mockCoverageWrapper = new Mock<ICoverageWrapper>();
@@ -53,7 +55,7 @@ namespace Coverlet.Collector.Tests
Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory = (TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule) =>
{
IServiceCollection serviceCollection = new ServiceCollection();
Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(f => f.Exists(It.IsAny<string>())).Returns((string testLib) => testLib == "abc.dll");
serviceCollection.AddTransient(_ => fileSystem.Object);
@@ -87,7 +89,7 @@ namespace Coverlet.Collector.Tests
Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory = (TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule) =>
{
IServiceCollection serviceCollection = new ServiceCollection();
Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(f => f.Exists(It.IsAny<string>())).Returns((string testLib) => testLib == "abc.dll");
serviceCollection.AddTransient(_ => fileSystem.Object);
@@ -114,7 +116,7 @@ namespace Coverlet.Collector.Tests
new Mock<ILogger>().Object,
new Mock<ISourceRootTranslator>().Object);
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = null,
IncludeDirectories = null,
@@ -126,7 +128,7 @@ namespace Coverlet.Collector.Tests
UseSourceLink = true
};
Coverage coverage = new Coverage("abc.dll", parameters, It.IsAny<ILogger>(), instrumentationHelper, new Mock<IFileSystem>().Object, new Mock<ISourceRootTranslator>().Object, new Mock<ICecilSymbolHelper>().Object);
var coverage = new Coverage("abc.dll", parameters, It.IsAny<ILogger>(), instrumentationHelper, new Mock<IFileSystem>().Object, new Mock<ISourceRootTranslator>().Object, new Mock<ICecilSymbolHelper>().Object);
sessionStartProperties.Add("TestSources", new List<string> { "abc.dll" });
_mockCoverageWrapper.Setup(x => x.CreateCoverage(It.IsAny<CoverletSettings>(), It.IsAny<ILogger>(), It.IsAny<IInstrumentationHelper>(), It.IsAny<IFileSystem>(), It.IsAny<ISourceRootTranslator>(), It.IsAny<ICecilSymbolHelper>())).Returns(coverage);
@@ -163,7 +165,7 @@ namespace Coverlet.Collector.Tests
string module = GetType().Assembly.Location;
string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb");
var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true);
File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true);
@@ -188,7 +190,7 @@ namespace Coverlet.Collector.Tests
Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory = (TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule) =>
{
IServiceCollection serviceCollection = new ServiceCollection();
Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(f => f.Exists(It.IsAny<string>())).Returns((string testLib) => testLib == "Test");
serviceCollection.AddTransient(_ => fileSystem.Object);
@@ -203,7 +205,7 @@ namespace Coverlet.Collector.Tests
_coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), new CoverageWrapper(), _mockCountDownEventFactory.Object, serviceCollectionFactory);
IList<IReporter> reporters = formats.Split(',').Select(f => new ReporterFactory(f).CreateReporter()).Where(x => x != null).ToList();
Mock<DataCollectionSink> mockDataCollectionSink = new Mock<DataCollectionSink>();
var mockDataCollectionSink = new Mock<DataCollectionSink>();
mockDataCollectionSink.Setup(m => m.SendFileAsync(It.IsAny<FileTransferInformation>())).Callback<FileTransferInformation>(fti =>
{
reporters.Remove(reporters.First(x =>
@@ -212,8 +214,8 @@ namespace Coverlet.Collector.Tests
});
var doc = new XmlDocument();
var root = doc.CreateElement("Configuration");
var element = doc.CreateElement("Format");
XmlElement root = doc.CreateElement("Configuration");
XmlElement element = doc.CreateElement("Format");
element.AppendChild(doc.CreateTextNode(formats));
root.AppendChild(element);
@@ -241,7 +243,7 @@ namespace Coverlet.Collector.Tests
Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory = (TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule) =>
{
IServiceCollection serviceCollection = new ServiceCollection();
Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(f => f.Exists(It.IsAny<string>())).Returns((string testLib) => testLib == "abc.dll");
serviceCollection.AddTransient(_ => fileSystem.Object);
@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Coverlet.Collector.DataCollection;
@@ -9,7 +12,7 @@ namespace Coverlet.Collector.Tests
{
public class CoverletSettingsParserTests
{
private CoverletSettingsParser _coverletSettingsParser;
private readonly CoverletSettingsParser _coverletSettingsParser;
public CoverletSettingsParserTests()
{
@@ -64,19 +67,19 @@ namespace Coverlet.Collector.Tests
{
var testModules = new List<string> { "abc.dll" };
var doc = new XmlDocument();
var configElement = doc.CreateElement("Configuration");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeFiltersElementName, includeFilters);
this.CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeFiltersElementName, excludeFilters);
this.CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName, includeDirectories);
this.CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeSourceFilesElementName, excludeSourceFiles);
this.CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeAttributesElementName, excludeAttributes);
this.CreateCoverletNodes(doc, configElement, CoverletConstants.MergeWithElementName, "/path/to/result.json");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.UseSourceLinkElementName, "false");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.SingleHitElementName, "true");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeTestAssemblyElementName, "true");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.SkipAutoProps, "true");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.DeterministicReport, "true");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.DoesNotReturnAttributesElementName, doesNotReturnAttributes);
XmlElement configElement = doc.CreateElement("Configuration");
CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeFiltersElementName, includeFilters);
CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeFiltersElementName, excludeFilters);
CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName, includeDirectories);
CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeSourceFilesElementName, excludeSourceFiles);
CreateCoverletNodes(doc, configElement, CoverletConstants.ExcludeAttributesElementName, excludeAttributes);
CreateCoverletNodes(doc, configElement, CoverletConstants.MergeWithElementName, "/path/to/result.json");
CreateCoverletNodes(doc, configElement, CoverletConstants.UseSourceLinkElementName, "false");
CreateCoverletNodes(doc, configElement, CoverletConstants.SingleHitElementName, "true");
CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeTestAssemblyElementName, "true");
CreateCoverletNodes(doc, configElement, CoverletConstants.SkipAutoProps, "true");
CreateCoverletNodes(doc, configElement, CoverletConstants.DeterministicReport, "true");
CreateCoverletNodes(doc, configElement, CoverletConstants.DoesNotReturnAttributesElementName, doesNotReturnAttributes);
CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules);
@@ -109,12 +112,12 @@ namespace Coverlet.Collector.Tests
{
var testModules = new List<string> { "abc.dll" };
var doc = new XmlDocument();
var configElement = doc.CreateElement("Configuration");
this.CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeFiltersElementName);
this.CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeFiltersElementName);
this.CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName);
this.CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeSourceFilesElementName);
this.CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeAttributesElementName);
XmlElement configElement = doc.CreateElement("Configuration");
CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeFiltersElementName);
CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeFiltersElementName);
CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName);
CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeSourceFilesElementName);
CreateCoverletNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeAttributesElementName);
CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules);
@@ -131,7 +134,7 @@ namespace Coverlet.Collector.Tests
{
var testModules = new List<string> { "abc.dll" };
var doc = new XmlDocument();
var configElement = doc.CreateElement("Configuration");
XmlElement configElement = doc.CreateElement("Configuration");
CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules);
@@ -160,8 +163,8 @@ namespace Coverlet.Collector.Tests
{
var testModules = new List<string> { "abc.dll" };
var doc = new XmlDocument();
var configElement = doc.CreateElement("Configuration");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.ReportFormatElementName, formats);
XmlElement configElement = doc.CreateElement("Configuration");
CreateCoverletNodes(doc, configElement, CoverletConstants.ReportFormatElementName, formats);
CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules);
@@ -175,10 +178,10 @@ namespace Coverlet.Collector.Tests
public void ParseShouldUseDefaultFormatWhenNoFormatSpecified(string formats)
{
var testModules = new List<string> { "abc.dll" };
var defaultFormat = CoverletConstants.DefaultReportFormat;
string defaultFormat = CoverletConstants.DefaultReportFormat;
var doc = new XmlDocument();
var configElement = doc.CreateElement("Configuration");
this.CreateCoverletNodes(doc, configElement, CoverletConstants.ReportFormatElementName, formats);
XmlElement configElement = doc.CreateElement("Configuration");
CreateCoverletNodes(doc, configElement, CoverletConstants.ReportFormatElementName, formats);
CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules);
@@ -187,14 +190,14 @@ namespace Coverlet.Collector.Tests
private void CreateCoverletNodes(XmlDocument doc, XmlElement configElement, string nodeSetting, string nodeValue)
{
var node = doc.CreateNode("element", nodeSetting, string.Empty);
XmlNode node = doc.CreateNode("element", nodeSetting, string.Empty);
node.InnerText = nodeValue;
configElement.AppendChild(node);
}
private void CreateCoverletNullInnerTextNodes(XmlDocument doc, XmlElement configElement, string nodeSetting)
{
var node = doc.CreateNode("element", nodeSetting, string.Empty);
XmlNode node = doc.CreateNode("element", nodeSetting, string.Empty);
node.InnerText = null;
configElement.AppendChild(node);
}
@@ -1,3 +1,6 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
[assembly: AssemblyKeyFile("coverlet.collector.tests.snk")]
@@ -0,0 +1,8 @@
# top-most EditorConfig file
# We don't want to import other EditorConfig files and we want
# to ensure no rules are enabled for these asset source files.
root = true
[*.cs]
# Default severity for all analyzer diagnostics
dotnet_analyzer_diagnostic.severity = none
@@ -0,0 +1,8 @@
# top-most EditorConfig file
# We don't want to import other EditorConfig files and we want
# to ensure no rules are enabled for these asset source files.
root = true
[*.cs]
# Default severity for all analyzer diagnostics
dotnet_analyzer_diagnostic.severity = none
@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Coverlet.Core;
using Moq;
using System.Linq;
using Xunit;
namespace Coverlet.Core.Tests
@@ -23,29 +21,29 @@ namespace Coverlet.Core.Tests
private void SetupDataForArithmeticPrecision()
{
Lines lines = new Lines();
var lines = new Lines();
lines.Add(1, 1);
for (int i = 2; i <= 6; i++)
{
lines.Add(i, 0);
}
Branches branches = new Branches();
var branches = new Branches();
branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 0, Ordinal = 1 });
for (int i = 2; i <= 6; i++)
{
branches.Add(new BranchInfo { Line = 1, Hits = 0, Offset = 1, Path = 1, Ordinal = (uint)i });
}
Methods methods = new Methods();
var methodString = "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()";
var methods = new Methods();
string methodString = "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()";
methods.Add(methodString, new Method());
methods[methodString].Lines = lines;
methods[methodString].Branches = branches;
Classes classes = new Classes();
var classes = new Classes();
classes.Add("Coverlet.Core.Tests.CoverageSummaryTests", methods);
Documents documents = new Documents();
var documents = new Documents();
documents.Add("doc.cs", classes);
_moduleArithmeticPrecision = new Modules();
@@ -54,23 +52,23 @@ namespace Coverlet.Core.Tests
private void SetupDataSingleModule()
{
Lines lines = new Lines();
var lines = new Lines();
lines.Add(1, 1);
lines.Add(2, 0);
Branches branches = new Branches();
var branches = new Branches();
branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 0, Ordinal = 1 });
branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 1, Ordinal = 2 });
Methods methods = new Methods();
var methodString = "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()";
var methods = new Methods();
string methodString = "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()";
methods.Add(methodString, new Method());
methods[methodString].Lines = lines;
methods[methodString].Branches = branches;
Classes classes = new Classes();
var classes = new Classes();
classes.Add("Coverlet.Core.Tests.CoverageSummaryTests", methods);
Documents documents = new Documents();
var documents = new Documents();
documents.Add("doc.cs", classes);
_averageCalculationSingleModule = new Modules();
@@ -79,21 +77,21 @@ namespace Coverlet.Core.Tests
private void SetupDataMultipleModule()
{
Lines lines = new Lines
var lines = new Lines
{
{ 1, 1 }, // covered
{ 2, 0 }, // not covered
{ 3, 0 } // not covered
};
Branches branches = new Branches
var branches = new Branches
{
new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 0, Ordinal = 1 }, // covered
new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 1, Ordinal = 2 }, // covered
new BranchInfo { Line = 1, Hits = 0, Offset = 1, Path = 1, Ordinal = 2 } // not covered
};
Methods methods = new Methods();
var methods = new Methods();
string[] methodString = {
"System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()", // covered
"System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestAditionalCalculateSummary()" // not covered
@@ -108,12 +106,12 @@ namespace Coverlet.Core.Tests
{ 1, 0 } // not covered
};
Classes classes = new Classes
var classes = new Classes
{
{ "Coverlet.Core.Tests.CoverageSummaryTests", methods }
};
Documents documents = new Documents
var documents = new Documents
{
{ "doc.cs", classes }
};
@@ -128,7 +126,7 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateLineCoverage_NoModules()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var modules = new Modules();
Assert.Equal(0, summary.CalculateLineCoverage(modules).Percent);
@@ -142,12 +140,12 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateLineCoverage_SingleModule()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var module = _averageCalculationSingleModule.First();
var document = module.Value.First();
var @class = document.Value.First();
var method = @class.Value.First();
System.Collections.Generic.KeyValuePair<string, Documents> module = _averageCalculationSingleModule.First();
System.Collections.Generic.KeyValuePair<string, Classes> document = module.Value.First();
System.Collections.Generic.KeyValuePair<string, Methods> @class = document.Value.First();
System.Collections.Generic.KeyValuePair<string, Method> method = @class.Value.First();
Assert.Equal(50, summary.CalculateLineCoverage(_averageCalculationSingleModule).AverageModulePercent);
Assert.Equal(50, summary.CalculateLineCoverage(module.Value).Percent);
@@ -159,9 +157,9 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateLineCoverage_MultiModule()
{
CoverageSummary summary = new CoverageSummary();
var documentsFirstModule = _averageCalculationMultiModule["module"];
var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
var summary = new CoverageSummary();
Documents documentsFirstModule = _averageCalculationMultiModule["module"];
Documents documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
Assert.Equal(37.5, summary.CalculateLineCoverage(_averageCalculationMultiModule).AverageModulePercent);
Assert.Equal(50, summary.CalculateLineCoverage(documentsFirstModule.First().Value).Percent);
@@ -174,12 +172,12 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateBranchCoverage_SingleModule()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var module = _averageCalculationSingleModule.First();
var document = module.Value.First();
var @class = document.Value.First();
var method = @class.Value.First();
System.Collections.Generic.KeyValuePair<string, Documents> module = _averageCalculationSingleModule.First();
System.Collections.Generic.KeyValuePair<string, Classes> document = module.Value.First();
System.Collections.Generic.KeyValuePair<string, Methods> @class = document.Value.First();
System.Collections.Generic.KeyValuePair<string, Method> method = @class.Value.First();
Assert.Equal(100, summary.CalculateBranchCoverage(_averageCalculationSingleModule).AverageModulePercent);
Assert.Equal(100, summary.CalculateBranchCoverage(module.Value).Percent);
@@ -191,9 +189,9 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateBranchCoverage_MultiModule()
{
CoverageSummary summary = new CoverageSummary();
var documentsFirstModule = _averageCalculationMultiModule["module"];
var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
var summary = new CoverageSummary();
Documents documentsFirstModule = _averageCalculationMultiModule["module"];
Documents documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
Assert.Equal(83.33, summary.CalculateBranchCoverage(_averageCalculationMultiModule).AverageModulePercent);
Assert.Equal(100, summary.CalculateBranchCoverage(documentsFirstModule.First().Value).Percent);
@@ -203,12 +201,12 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateMethodCoverage_SingleModule()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var module = _averageCalculationSingleModule.First();
var document = module.Value.First();
var @class = document.Value.First();
var method = @class.Value.First();
System.Collections.Generic.KeyValuePair<string, Documents> module = _averageCalculationSingleModule.First();
System.Collections.Generic.KeyValuePair<string, Classes> document = module.Value.First();
System.Collections.Generic.KeyValuePair<string, Methods> @class = document.Value.First();
System.Collections.Generic.KeyValuePair<string, Method> method = @class.Value.First();
Assert.Equal(100, summary.CalculateMethodCoverage(_averageCalculationSingleModule).AverageModulePercent);
Assert.Equal(100, summary.CalculateMethodCoverage(module.Value).Percent);
@@ -220,9 +218,9 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateMethodCoverage_MultiModule()
{
CoverageSummary summary = new CoverageSummary();
var documentsFirstModule = _averageCalculationMultiModule["module"];
var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
var summary = new CoverageSummary();
Documents documentsFirstModule = _averageCalculationMultiModule["module"];
Documents documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];
Assert.Equal(75, summary.CalculateMethodCoverage(_averageCalculationMultiModule).AverageModulePercent);
Assert.Equal(100, summary.CalculateMethodCoverage(documentsFirstModule.First().Value).Percent);
@@ -232,12 +230,12 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateLineCoveragePercentage_ArithmeticPrecisionCheck()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var module = _moduleArithmeticPrecision.First();
var document = module.Value.First();
var @class = document.Value.First();
var method = @class.Value.First();
System.Collections.Generic.KeyValuePair<string, Documents> module = _moduleArithmeticPrecision.First();
System.Collections.Generic.KeyValuePair<string, Classes> document = module.Value.First();
System.Collections.Generic.KeyValuePair<string, Methods> @class = document.Value.First();
System.Collections.Generic.KeyValuePair<string, Method> method = @class.Value.First();
Assert.Equal(16.66, summary.CalculateLineCoverage(_moduleArithmeticPrecision).AverageModulePercent);
Assert.Equal(16.66, summary.CalculateLineCoverage(module.Value).Percent);
@@ -249,12 +247,12 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCalculateBranchCoveragePercentage_ArithmeticPrecisionCheck()
{
CoverageSummary summary = new CoverageSummary();
var summary = new CoverageSummary();
var module = _moduleArithmeticPrecision.First();
var document = module.Value.First();
var @class = document.Value.First();
var method = @class.Value.First();
System.Collections.Generic.KeyValuePair<string, Documents> module = _moduleArithmeticPrecision.First();
System.Collections.Generic.KeyValuePair<string, Classes> document = module.Value.First();
System.Collections.Generic.KeyValuePair<string, Methods> @class = document.Value.First();
System.Collections.Generic.KeyValuePair<string, Method> method = @class.Value.First();
Assert.Equal(16.66, summary.CalculateBranchCoverage(_moduleArithmeticPrecision).AverageModulePercent);
Assert.Equal(16.66, summary.CalculateBranchCoverage(module.Value).Percent);
@@ -1,10 +1,10 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -146,7 +146,7 @@ namespace Coverlet.Core.Tests
return 0;
}, new string[] { path });
var document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
Core.Instrumentation.Document document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
document.AssertLinesCovered(BuildConfiguration.Debug, (133, 1), (134, 1), (135, 1), (136, 1), (137, 1));
Assert.DoesNotContain(document.Branches, x => x.Key.Line == 134);
}
@@ -174,7 +174,7 @@ namespace Coverlet.Core.Tests
return 0;
}, new string[] { path });
var document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
Core.Instrumentation.Document document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
document.AssertLinesCovered(BuildConfiguration.Debug, (150, 1));
Assert.DoesNotContain(document.Branches, x => x.Key.Line == 150);
}
@@ -203,7 +203,7 @@ namespace Coverlet.Core.Tests
return 0;
}, new string[] { path });
var document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
Core.Instrumentation.Document document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs");
document.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 170, 176);
document.AssertBranchesCovered(BuildConfiguration.Debug, (171, 0, 1), (171, 1, 1));
Assert.DoesNotContain(document.Branches, x => x.Key.Line == 176);
@@ -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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -1,10 +1,10 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -1,9 +1,9 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Xunit;
@@ -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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -64,7 +65,7 @@ namespace Coverlet.Core.Tests
return 0;
}, new string[] { path });
var res = TestInstrumentationHelper.GetCoverageResult(path);
CoverageResult res = TestInstrumentationHelper.GetCoverageResult(path);
res.Document("Instrumentation.CatchBlock.cs")
.AssertLinesCoveredAllBut(BuildConfiguration.Debug, 45, 59, 113, 127, 137, 138, 139, 153, 154, 155, 156, 175, 189, 199, 200, 201, 222, 223, 224, 225, 252, 266, 335, 349)
.ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 6)
@@ -1,4 +1,7 @@
using System;
// 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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
@@ -1,14 +1,14 @@
// 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.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Samples.Tests;
using Coverlet.Core.Symbols;
using Coverlet.Tests.Xunit.Extensions;
using Moq;
using Xunit;
@@ -19,7 +19,7 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestCoverageSkipModule__AssemblyMarkedAsExcludeFromCodeCoverage()
{
Mock<FileSystem> partialMockFileSystem = new Mock<FileSystem>();
var partialMockFileSystem = new Mock<FileSystem>();
partialMockFileSystem.CallBase = true;
partialMockFileSystem.Setup(fs => fs.NewFileStream(It.IsAny<string>(), It.IsAny<FileMode>(), It.IsAny<FileAccess>())).Returns((string path, FileMode mode, FileAccess access) =>
{
@@ -29,11 +29,11 @@ namespace Coverlet.Core.Tests
string excludedbyattributeDll = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), "coverlet.tests.projectsample.excludedbyattribute.dll").First();
InstrumentationHelper instrumentationHelper =
var instrumentationHelper =
new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object,
new SourceRootTranslator(excludedbyattributeDll, new Mock<ILogger>().Object, new FileSystem()));
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = new string[] { "[coverlet.tests.projectsample.excludedbyattribute*]*" },
IncludeDirectories = Array.Empty<string>(),
@@ -74,7 +74,7 @@ namespace Coverlet.Core.Tests
CoverageResult result = TestInstrumentationHelper.GetCoverageResult(path);
var document = result.Document("Instrumentation.ExcludeFromCoverage.cs");
Core.Instrumentation.Document document = result.Document("Instrumentation.ExcludeFromCoverage.cs");
// Invoking method "Test" of class "MethodsWithExcludeFromCodeCoverageAttr" we expect to cover 100% lines for MethodsWithExcludeFromCodeCoverageAttr
Assert.DoesNotContain(document.Lines, l =>
@@ -1,10 +1,11 @@
// 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.IO;
using System.Reflection;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -1,4 +1,7 @@
using System.IO;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Instrumentation;
using Moq;
@@ -11,7 +14,7 @@ namespace Coverlet.Core.Tests
[Fact]
public void CoverageResult_NegativeLineCoverage_TranslatedToMaxValueOfInt32()
{
InstrumenterResult instrumenterResult = new InstrumenterResult
var instrumenterResult = new InstrumenterResult
{
HitsFilePath = "HitsFilePath",
SourceLink = "SourceLink",
@@ -36,7 +39,7 @@ namespace Coverlet.Core.Tests
instrumenterResult.Documents.Add("document", document);
CoveragePrepareResult coveragePrepareResult = new CoveragePrepareResult
var coveragePrepareResult = new CoveragePrepareResult
{
UseSourceLink = true,
Results = new[] {instrumenterResult},
@@ -44,7 +47,7 @@ namespace Coverlet.Core.Tests
};
Stream memoryStream = new MemoryStream();
BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
var binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write(1);
binaryWriter.Write(-1);
memoryStream.Position = 0;
@@ -57,7 +60,7 @@ namespace Coverlet.Core.Tests
var coverage = new Coverage(coveragePrepareResult, new Mock<ILogger>().Object, new Mock<IInstrumentationHelper>().Object,
fileSystemMock.Object, new Mock<ISourceRootTranslator>().Object);
var coverageResult = coverage.GetCoverageResult();
CoverageResult coverageResult = coverage.GetCoverageResult();
coverageResult.Document("document").AssertLinesCovered(BuildConfiguration.Debug, (1, int.MaxValue));
}
@@ -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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Xunit;
namespace Coverlet.Core.Tests
@@ -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.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Coverlet.Tests.Xunit.Extensions;
using Tmds.Utils;
using Xunit;
@@ -1,6 +1,8 @@
using System.IO;
using System.Threading.Tasks;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Threading.Tasks;
using Coverlet.Core.Samples.Tests;
using Tmds.Utils;
using Xunit;
@@ -19,7 +21,7 @@ namespace Coverlet.Core.Tests
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<Yield>(instance =>
{
foreach (var _ in instance.One()) ;
foreach (dynamic _ in instance.One()) ;
return Task.CompletedTask;
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -50,7 +52,7 @@ namespace Coverlet.Core.Tests
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<Yield>(instance =>
{
foreach (var _ in instance.Two()) ;
foreach (dynamic _ in instance.Two()) ;
return Task.CompletedTask;
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -80,7 +82,7 @@ namespace Coverlet.Core.Tests
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<Yield>(instance =>
{
foreach (var _ in instance.OneWithSwitch(2)) ;
foreach (dynamic _ in instance.OneWithSwitch(2)) ;
return Task.CompletedTask;
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -111,7 +113,7 @@ namespace Coverlet.Core.Tests
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<Yield>(instance =>
{
foreach (var _ in instance.Three()) ;
foreach (dynamic _ in instance.Three()) ;
return Task.CompletedTask;
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -141,7 +143,7 @@ namespace Coverlet.Core.Tests
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<Yield>(instance =>
{
foreach (var _ in instance.Enumerable(new[] { "one", "two", "three", "four" })) ;
foreach (dynamic _ in instance.Enumerable(new[] { "one", "two", "three", "four" })) ;
return Task.CompletedTask;
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -1,6 +1,8 @@
// 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.IO;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Symbols;
@@ -19,17 +21,17 @@ namespace Coverlet.Core.Tests
string module = GetType().Assembly.Location;
string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb");
var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true);
File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true);
// TODO: Find a way to mimick hits
InstrumentationHelper instrumentationHelper =
var instrumentationHelper =
new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object,
new SourceRootTranslator(module, new Mock<ILogger>().Object, new FileSystem()));
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = new string[] { "[coverlet.tests.projectsample.excludedbyattribute*]*" },
IncludeDirectories = Array.Empty<string>(),
@@ -45,7 +47,7 @@ namespace Coverlet.Core.Tests
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();
var result = coverage.GetCoverageResult();
CoverageResult result = coverage.GetCoverageResult();
Assert.Empty(result.Modules);
@@ -58,16 +60,16 @@ namespace Coverlet.Core.Tests
string module = GetType().Assembly.Location;
string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb");
var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true);
File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true);
InstrumentationHelper instrumentationHelper =
var instrumentationHelper =
new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object,
new SourceRootTranslator(module, new Mock<ILogger>().Object, new FileSystem()));
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = Array.Empty<string>(),
IncludeDirectories = Array.Empty<string>(),
@@ -84,7 +86,7 @@ namespace Coverlet.Core.Tests
new SourceRootTranslator(module, _mockLogger.Object, new FileSystem()), new CecilSymbolHelper());
coverage.PrepareModules();
var result = coverage.GetCoverageResult();
CoverageResult result = coverage.GetCoverageResult();
Assert.NotEmpty(result.Modules);
@@ -1,10 +1,12 @@
using Coverlet.Core.Instrumentation;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Coverlet.Core.Instrumentation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using Xunit.Sdk;
@@ -90,18 +92,18 @@ namespace Coverlet.Core.Tests
if (document.Lines.Values.All(l => l.Method != methodName) && document.Branches.Values.All(l => l.Method != methodName))
{
var methods = document.Lines.Values.Select(l => $"'{l.Method}'")
IEnumerable<string> methods = document.Lines.Values.Select(l => $"'{l.Method}'")
.Concat(document.Branches.Values.Select(b => $"'{b.Method}'"))
.Distinct();
throw new XunitException($"Method '{methodName}' not found. Methods in document: {string.Join(", ", methods)}");
}
foreach (var line in document.Lines.Where(l => l.Value.Method == methodName))
foreach (KeyValuePair<int, Line> line in document.Lines.Where(l => l.Value.Method == methodName))
{
methodDoc.Lines[line.Key] = line.Value;
}
foreach (var branch in document.Branches.Where(b => b.Value.Method == methodName))
foreach (KeyValuePair<BranchKey, Branch> branch in document.Branches.Where(b => b.Value.Method == methodName))
{
methodDoc.Branches[branch.Key] = branch.Value;
}
@@ -150,7 +152,7 @@ namespace Coverlet.Core.Tests
throw new ArgumentNullException(nameof(document));
}
StringBuilder builder = new StringBuilder();
var builder = new StringBuilder();
foreach (KeyValuePair<BranchKey, Branch> branch in document.Branches)
{
builder.AppendLine($"({branch.Value.Number}, {branch.Value.Ordinal}, {branch.Value.Hits}),");
@@ -172,7 +174,7 @@ namespace Coverlet.Core.Tests
return document;
}
List<string> branchesToCover = new List<string>(lines.Select(b => $"[line {b.line} ordinal {b.ordinal}]"));
var branchesToCover = new List<string>(lines.Select(b => $"[line {b.line} ordinal {b.ordinal}]"));
foreach (KeyValuePair<BranchKey, Branch> branch in document.Branches)
{
foreach ((int lineToCheck, int ordinalToCheck, int expectedHits) in lines)
@@ -270,7 +272,7 @@ namespace Coverlet.Core.Tests
throw new ArgumentException("to cannot be lower than from");
}
List<int> lines = new List<int>();
var lines = new List<int>();
foreach (KeyValuePair<int, Line> line in document.Lines)
{
if (line.Value.Number >= from && line.Value.Number <= to && line.Value.Hits > 0)
@@ -301,7 +303,7 @@ namespace Coverlet.Core.Tests
return document;
}
List<int> linesToCover = new List<int>(lines.Select(l => l.line));
var linesToCover = new List<int>(lines.Select(l => l.line));
foreach (KeyValuePair<int, Line> line in document.Lines)
{
foreach ((int lineToCheck, int expectedHits) in lines)
@@ -349,7 +351,7 @@ namespace Coverlet.Core.Tests
return document;
}
List<int> linesToCover = new List<int>(lines);
var linesToCover = new List<int>(lines);
foreach (KeyValuePair<int, Line> line in document.Lines)
{
foreach (int lineToCheck in lines)
@@ -409,7 +411,7 @@ namespace Coverlet.Core.Tests
return document;
}
var unexpectedlyInstrumented = document.Lines.Select(l => l.Value.Number).Intersect(lines);
IEnumerable<int> unexpectedlyInstrumented = document.Lines.Select(l => l.Value.Number).Intersect(lines);
if (unexpectedlyInstrumented.Any())
{
@@ -435,7 +437,7 @@ namespace Coverlet.Core.Tests
var instrumentedLines = document.Lines.Select(l => l.Value.Number).ToHashSet();
var missing = lines.Where(l => !instrumentedLines.Contains(l));
IEnumerable<int> missing = lines.Where(l => !instrumentedLines.Contains(l));
if (missing.Any())
{
@@ -1,4 +1,7 @@
using System;
// 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.Generic;
using System.IO;
using System.Linq;
@@ -28,7 +31,7 @@ namespace Coverlet.Core.Tests
/// </summary>
public static void GenerateHtmlReport(CoverageResult coverageResult, IReporter reporter = null, string sourceFileFilter = "", [CallerMemberName] string directory = "")
{
JsonReporter defaultReporter = new JsonReporter();
var defaultReporter = new JsonReporter();
reporter ??= new CoberturaReporter();
DirectoryInfo dir = Directory.CreateDirectory(directory);
dir.Delete(true);
@@ -62,12 +65,12 @@ namespace Coverlet.Core.Tests
Assert.DoesNotContain("not found for module: ", message);
});
_processWideContainer.GetRequiredService<IInstrumentationHelper>().SetLogger(logger.Object);
CoveragePrepareResult coveragePrepareResultLoaded = CoveragePrepareResult.Deserialize(result);
Coverage coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, _processWideContainer.GetService<IInstrumentationHelper>(), new FileSystem(), new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
var coveragePrepareResultLoaded = CoveragePrepareResult.Deserialize(result);
var coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, _processWideContainer.GetService<IInstrumentationHelper>(), new FileSystem(), new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
return coverage.GetCoverageResult();
}
async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callMethod,
public static async Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callMethod,
Func<string, string[]> includeFilter = null,
Func<string, string[]> excludeFilter = null,
Func<string, string[]> doesNotReturnAttributes = null,
@@ -93,7 +96,7 @@ namespace Coverlet.Core.Tests
static string[] defaultFilters(string _) => Array.Empty<string>();
CoverageParameters parameters = new CoverageParameters
var parameters = new CoverageParameters
{
IncludeFilters = (includeFilter is null ? defaultFilters(fileName) : includeFilter(fileName)).Concat(
new string[]
@@ -117,14 +120,14 @@ namespace Coverlet.Core.Tests
};
// Instrument module
Coverage coverage = new Coverage(newPath, parameters, new Logger(logFile),
var coverage = new Coverage(newPath, parameters, new Logger(logFile),
_processWideContainer.GetService<IInstrumentationHelper>(), _processWideContainer.GetService<IFileSystem>(), _processWideContainer.GetService<ISourceRootTranslator>(), _processWideContainer.GetService<ICecilSymbolHelper>());
CoveragePrepareResult prepareResult = coverage.PrepareModules();
Assert.Single(prepareResult.Results);
// Load new assembly
Assembly asm = Assembly.LoadFile(newPath);
var asm = Assembly.LoadFile(newPath);
// Instance type and call method
await callMethod(Activator.CreateInstance(asm.GetType(typeof(T).FullName)));
@@ -140,7 +143,7 @@ namespace Coverlet.Core.Tests
tracker.GetTypeInfo().GetMethod("UnloadModule").Invoke(null, new object[2] { null, null });
// Persist CoveragePrepareResult
using (FileStream fs = new FileStream(persistPrepareResultToFile, FileMode.Open))
using (var fs = new FileStream(persistPrepareResultToFile, FileMode.Open))
{
await CoveragePrepareResult.Serialize(prepareResult).CopyToAsync(fs);
}
@@ -237,7 +240,7 @@ namespace Coverlet.Core.Tests
// We log to files for debugging pourpose, we can check if instrumentation is ok
class Logger : ILogger
{
string _logFile;
readonly string _logFile;
public Logger(string logFile) => _logFile = logFile;
+29 -26
View File
@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Coverlet.Core.Enums;
using Xunit;
@@ -6,22 +9,22 @@ namespace Coverlet.Core.Tests
{
public class CoverageResultTests
{
private Modules _modules;
private readonly Modules _modules;
public CoverageResultTests()
{
Lines lines = new Lines();
var lines = new Lines();
lines.Add(1, 1);
lines.Add(2, 1);
lines.Add(3, 1);
Branches branches = new Branches();
var branches = new Branches();
branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 0, Ordinal = 1 });
branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 1, Path = 1, Ordinal = 2 });
branches.Add(new BranchInfo { Line = 2, Hits = 0, Offset = 1, Path = 0, Ordinal = 1 });
// System.Void Coverlet.Core.Tests.CoverageResultTests::CoverageResultTests - 3/3 100% line 2/3 66.7% branch coverage
Methods methods = new Methods();
var methodString = "System.Void Coverlet.Core.Tests.CoverageResultTests::CoverageResultTests()";
var methods = new Methods();
string methodString = "System.Void Coverlet.Core.Tests.CoverageResultTests::CoverageResultTests()";
methods.Add(methodString, new Method());
methods[methodString].Lines = lines;
methods[methodString].Branches = branches;
@@ -35,13 +38,13 @@ namespace Coverlet.Core.Tests
{2, 0},
};
Classes classes = new Classes();
var classes = new Classes();
classes.Add("Coverlet.Core.Tests.CoverageResultTests", methods);
// Methods - 1/2 (50%)
// Lines - 3/5 (60%)
// Branches - 2/3 (66.67%)
Documents documents = new Documents();
var documents = new Documents();
documents.Add("doc.cs", classes);
_modules = new Modules();
@@ -51,11 +54,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdLine()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = _modules;
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 90 },
{ ThresholdTypeFlags.Method, 10 },
@@ -71,11 +74,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdMethod()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = _modules;
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 50 },
{ ThresholdTypeFlags.Method, 75 },
@@ -91,11 +94,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdBranch()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = _modules;
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 50 },
{ ThresholdTypeFlags.Method, 50 },
@@ -111,11 +114,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdAllGood()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = _modules;
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 50 },
{ ThresholdTypeFlags.Method, 50 },
@@ -131,11 +134,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdAllFail()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = _modules;
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 100 },
{ ThresholdTypeFlags.Method, 100 },
@@ -152,11 +155,11 @@ namespace Coverlet.Core.Tests
[Fact]
public void TestGetThresholdTypesBelowThresholdWhenNoModuleInstrumented()
{
CoverageResult result = new CoverageResult();
var result = new CoverageResult();
result.Modules = new Modules();
CoverageSummary summary = new CoverageSummary();
Dictionary<ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
var summary = new CoverageSummary();
var thresholdTypeFlagValues = new Dictionary<ThresholdTypeFlags, double>()
{
{ ThresholdTypeFlags.Line, 80 },
{ ThresholdTypeFlags.Method, 80 },

Some files were not shown because too many files have changed in this diff Show More