diff --git a/src/coverlet.console/Program.cs b/src/coverlet.console/Program.cs index e26ab1199..271346af6 100644 --- a/src/coverlet.console/Program.cs +++ b/src/coverlet.console/Program.cs @@ -168,9 +168,17 @@ static int Main(string[] args) var summary = new CoverageSummary(); int numModules = result.Modules.Count; - var totalLinePercent = summary.CalculateLineCoverage(result.Modules).Percent; - var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent; - var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent; + var linePercentCalculation = summary.CalculateLineCoverage(result.Modules); + var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules); + var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules); + + var totalLinePercent = linePercentCalculation.Percent; + var totalBranchPercent = branchPercentCalculation.Percent; + var totalMethodPercent = methodPercentCalculation.Percent; + + var averageLinePercent = linePercentCalculation.AverageModulePercent; + var averageBranchPercent = branchPercentCalculation.AverageModulePercent; + var averageMethodPercent = methodPercentCalculation.AverageModulePercent; foreach (var _module in result.Modules) { @@ -188,7 +196,7 @@ static int Main(string[] args) coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" }); coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%"); - coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%"); + coverageTable.AddRow("Average", $"{averageLinePercent}%", $"{averageBranchPercent}%", $"{averageMethodPercent}%"); logger.LogInformation(coverageTable.ToStringAlternative()); diff --git a/src/coverlet.core/CoverageDetails.cs b/src/coverlet.core/CoverageDetails.cs index d48d733a7..6134e79b4 100644 --- a/src/coverlet.core/CoverageDetails.cs +++ b/src/coverlet.core/CoverageDetails.cs @@ -4,8 +4,15 @@ namespace Coverlet.Core { public class CoverageDetails { + private double _averageModulePercent; public double Covered { get; internal set; } public int Total { get; internal set; } + public double AverageModulePercent + { + get { return Math.Floor(_averageModulePercent * 100) / 100; } + internal set { _averageModulePercent = value; } + } + public double Percent => Total == 0 ? 100D : Math.Floor((Covered / Total) * 10000) / 100; } } \ No newline at end of file diff --git a/src/coverlet.core/CoverageResult.cs b/src/coverlet.core/CoverageResult.cs index 127f33d7b..264eafe8f 100644 --- a/src/coverlet.core/CoverageResult.cs +++ b/src/coverlet.core/CoverageResult.cs @@ -170,9 +170,9 @@ public ThresholdTypeFlags GetThresholdTypesBelowThreshold(CoverageSummary summar { foreach (var module in Modules) { - var line = summary.CalculateLineCoverage(module.Value).Percent; - var branch = summary.CalculateBranchCoverage(module.Value).Percent; - var method = summary.CalculateMethodCoverage(module.Value).Percent; + double line = summary.CalculateLineCoverage(module.Value).Percent; + double branch = summary.CalculateBranchCoverage(module.Value).Percent; + double method = summary.CalculateMethodCoverage(module.Value).Percent; if ((thresholdTypes & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None) { @@ -196,42 +196,34 @@ public ThresholdTypeFlags GetThresholdTypesBelowThreshold(CoverageSummary summar break; case ThresholdStatistic.Average: { - double line = 0; - double branch = 0; - double method = 0; - int numModules = Modules.Count; - - foreach (var module in Modules) - { - line += summary.CalculateLineCoverage(module.Value).Percent; - branch += summary.CalculateBranchCoverage(module.Value).Percent; - method += summary.CalculateMethodCoverage(module.Value).Percent; - } + double line = summary.CalculateLineCoverage(Modules).AverageModulePercent; + double branch = summary.CalculateBranchCoverage(Modules).AverageModulePercent; + double method = summary.CalculateMethodCoverage(Modules).AverageModulePercent; if ((thresholdTypes & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None) { - if ((line / numModules) < threshold) + if (line < threshold) thresholdTypeFlags |= ThresholdTypeFlags.Line; } if ((thresholdTypes & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None) { - if ((branch / numModules) < threshold) + if (branch < threshold) thresholdTypeFlags |= ThresholdTypeFlags.Branch; } if ((thresholdTypes & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None) { - if ((method / numModules) < threshold) + if (method < threshold) thresholdTypeFlags |= ThresholdTypeFlags.Method; } } break; case ThresholdStatistic.Total: { - var line = summary.CalculateLineCoverage(Modules).Percent; - var branch = summary.CalculateBranchCoverage(Modules).Percent; - var method = summary.CalculateMethodCoverage(Modules).Percent; + double line = summary.CalculateLineCoverage(Modules).Percent; + double branch = summary.CalculateBranchCoverage(Modules).Percent; + double method = summary.CalculateMethodCoverage(Modules).Percent; if ((thresholdTypes & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None) { diff --git a/src/coverlet.core/CoverageSummary.cs b/src/coverlet.core/CoverageSummary.cs index 94ab2fb8b..1a266e28a 100644 --- a/src/coverlet.core/CoverageSummary.cs +++ b/src/coverlet.core/CoverageSummary.cs @@ -53,12 +53,15 @@ public CoverageDetails CalculateLineCoverage(Documents documents) public CoverageDetails CalculateLineCoverage(Modules modules) { var details = new CoverageDetails(); + var accumPercent = 0.0D; foreach (var module in modules) { var moduleCoverage = CalculateLineCoverage(module.Value); details.Covered += moduleCoverage.Covered; details.Total += moduleCoverage.Total; + accumPercent += moduleCoverage.Percent; } + details.AverageModulePercent = accumPercent / modules.Count; return details; } @@ -149,12 +152,15 @@ public CoverageDetails CalculateBranchCoverage(Documents documents) public CoverageDetails CalculateBranchCoverage(Modules modules) { var details = new CoverageDetails(); + var accumPercent = 0.0D; foreach (var module in modules) { var moduleCoverage = CalculateBranchCoverage(module.Value); details.Covered += moduleCoverage.Covered; details.Total += moduleCoverage.Total; + accumPercent += moduleCoverage.Percent; } + details.AverageModulePercent = accumPercent / modules.Count; return details; } @@ -206,12 +212,15 @@ public CoverageDetails CalculateMethodCoverage(Documents documents) public CoverageDetails CalculateMethodCoverage(Modules modules) { var details = new CoverageDetails(); + var accumPercent = 0.0D; foreach (var module in modules) { var moduleCoverage = CalculateMethodCoverage(module.Value); details.Covered += moduleCoverage.Covered; details.Total += moduleCoverage.Total; + accumPercent += moduleCoverage.Percent; } + details.AverageModulePercent = accumPercent / modules.Count; return details; } } diff --git a/test/coverlet.core.tests/CoverageSummaryTests.cs b/test/coverlet.core.tests/CoverageSummaryTests.cs index 783b26ae1..9dc9bf5a4 100644 --- a/test/coverlet.core.tests/CoverageSummaryTests.cs +++ b/test/coverlet.core.tests/CoverageSummaryTests.cs @@ -10,12 +10,14 @@ namespace Coverlet.Core.Tests { public class CoverageSummaryTests { - private Modules _modules; + private Modules _averageCalculationSingleModule; + private Modules _averageCalculationMultiModule; private Modules _moduleArithmeticPrecision; public CoverageSummaryTests() { - SetupData(); + SetupDataSingleModule(); + SetupDataMultipleModule(); SetupDataForArithmeticPrecision(); } @@ -50,7 +52,7 @@ private void SetupDataForArithmeticPrecision() _moduleArithmeticPrecision.Add("module", documents); } - private void SetupData() + private void SetupDataSingleModule() { Lines lines = new Lines(); lines.Add(1, 1); @@ -71,20 +73,69 @@ private void SetupData() Documents documents = new Documents(); documents.Add("doc.cs", classes); - _modules = new Modules(); - _modules.Add("module", documents); + _averageCalculationSingleModule = new Modules(); + _averageCalculationSingleModule.Add("module", documents); + } + + private void SetupDataMultipleModule() + { + Lines lines = new Lines + { + { 1, 1 }, // covered + { 2, 0 }, // not covered + { 3, 0 } // not covered + }; + + Branches 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(); + string[] methodString = { + "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestCalculateSummary()", // covered + "System.Void Coverlet.Core.Tests.CoverageSummaryTests::TestAditionalCalculateSummary()" // not covered + }; + methods.Add(methodString[0], new Method()); + methods[methodString[0]].Lines = lines; + methods[methodString[0]].Branches = branches; + + methods.Add(methodString[1], new Method()); + methods[methodString[1]].Lines = new Lines + { + { 1, 0 } // not covered + }; + + Classes classes = new Classes + { + { "Coverlet.Core.Tests.CoverageSummaryTests", methods } + }; + + Documents documents = new Documents + { + { "doc.cs", classes } + }; + + _averageCalculationMultiModule = new Modules + { + { "module", _averageCalculationSingleModule["module"] }, + { "aditionalModule", documents } + }; } [Fact] - public void TestCalculateLineCoverage() + public void TestCalculateLineCoverage_SingleModule() { CoverageSummary summary = new CoverageSummary(); - var module = _modules.First(); + var module = _averageCalculationSingleModule.First(); var document = module.Value.First(); var @class = document.Value.First(); var method = @class.Value.First(); + Assert.Equal(50, summary.CalculateLineCoverage(_averageCalculationSingleModule).AverageModulePercent); Assert.Equal(50, summary.CalculateLineCoverage(module.Value).Percent); Assert.Equal(50, summary.CalculateLineCoverage(document.Value).Percent); Assert.Equal(50, summary.CalculateLineCoverage(@class.Value).Percent); @@ -92,15 +143,31 @@ public void TestCalculateLineCoverage() } [Fact] - public void TestCalculateBranchCoverage() + public void TestCalculateLineCoverage_MultiModule() + { + CoverageSummary summary = new CoverageSummary(); + var documentsFirstModule = _averageCalculationMultiModule["module"]; + var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"]; + + Assert.Equal(37.5, summary.CalculateLineCoverage(_averageCalculationMultiModule).AverageModulePercent); + Assert.Equal(50, summary.CalculateLineCoverage(documentsFirstModule.First().Value).Percent); + + Assert.Equal(33.33, summary.CalculateLineCoverage(documentsSecondModule.First().Value.First().Value.ElementAt(0).Value.Lines).Percent); // covered 1 of 3 + Assert.Equal(0, summary.CalculateLineCoverage(documentsSecondModule.First().Value.First().Value.ElementAt(1).Value.Lines).Percent); // covered 0 of 1 + Assert.Equal(25, summary.CalculateLineCoverage(documentsSecondModule.First().Value).Percent); // covered 1 of 4 lines + } + + [Fact] + public void TestCalculateBranchCoverage_SingleModule() { CoverageSummary summary = new CoverageSummary(); - var module = _modules.First(); + var module = _averageCalculationSingleModule.First(); var document = module.Value.First(); var @class = document.Value.First(); var method = @class.Value.First(); + Assert.Equal(100, summary.CalculateBranchCoverage(_averageCalculationSingleModule).AverageModulePercent); Assert.Equal(100, summary.CalculateBranchCoverage(module.Value).Percent); Assert.Equal(100, summary.CalculateBranchCoverage(document.Value).Percent); Assert.Equal(100, summary.CalculateBranchCoverage(@class.Value).Percent); @@ -108,21 +175,46 @@ public void TestCalculateBranchCoverage() } [Fact] - public void TestCalculateMethodCoverage() + public void TestCalculateBranchCoverage_MultiModule() { CoverageSummary summary = new CoverageSummary(); + var documentsFirstModule = _averageCalculationMultiModule["module"]; + var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"]; - var module = _modules.First(); + Assert.Equal(83.33, summary.CalculateBranchCoverage(_averageCalculationMultiModule).AverageModulePercent); + Assert.Equal(100, summary.CalculateBranchCoverage(documentsFirstModule.First().Value).Percent); + Assert.Equal(66.66, summary.CalculateBranchCoverage(documentsSecondModule.First().Value).Percent); + } + + [Fact] + public void TestCalculateMethodCoverage_SingleModule() + { + CoverageSummary summary = new CoverageSummary(); + + var module = _averageCalculationSingleModule.First(); var document = module.Value.First(); var @class = document.Value.First(); var method = @class.Value.First(); + Assert.Equal(100, summary.CalculateMethodCoverage(_averageCalculationSingleModule).AverageModulePercent); Assert.Equal(100, summary.CalculateMethodCoverage(module.Value).Percent); Assert.Equal(100, summary.CalculateMethodCoverage(document.Value).Percent); Assert.Equal(100, summary.CalculateMethodCoverage(@class.Value).Percent); Assert.Equal(100, summary.CalculateMethodCoverage(method.Value.Lines).Percent); } + [Fact] + public void TestCalculateMethodCoverage_MultiModule() + { + CoverageSummary summary = new CoverageSummary(); + var documentsFirstModule = _averageCalculationMultiModule["module"]; + var documentsSecondModule = _averageCalculationMultiModule["aditionalModule"]; + + Assert.Equal(75, summary.CalculateMethodCoverage(_averageCalculationMultiModule).AverageModulePercent); + Assert.Equal(100, summary.CalculateMethodCoverage(documentsFirstModule.First().Value).Percent); + Assert.Equal(50, summary.CalculateMethodCoverage(documentsSecondModule.First().Value).Percent); + } + [Fact] public void TestCalculateLineCoveragePercentage_ArithmeticPrecisionCheck() { @@ -133,6 +225,7 @@ public void TestCalculateLineCoveragePercentage_ArithmeticPrecisionCheck() var @class = document.Value.First(); var method = @class.Value.First(); + Assert.Equal(16.66, summary.CalculateLineCoverage(_moduleArithmeticPrecision).AverageModulePercent); Assert.Equal(16.66, summary.CalculateLineCoverage(module.Value).Percent); Assert.Equal(16.66, summary.CalculateLineCoverage(document.Value).Percent); Assert.Equal(16.66, summary.CalculateLineCoverage(@class.Value).Percent); @@ -149,6 +242,7 @@ public void TestCalculateBranchCoveragePercentage_ArithmeticPrecisionCheck() var @class = document.Value.First(); var method = @class.Value.First(); + Assert.Equal(16.66, summary.CalculateBranchCoverage(_moduleArithmeticPrecision).AverageModulePercent); Assert.Equal(16.66, summary.CalculateBranchCoverage(module.Value).Percent); Assert.Equal(16.66, summary.CalculateBranchCoverage(document.Value).Percent); Assert.Equal(16.66, summary.CalculateBranchCoverage(@class.Value).Percent);