diff --git a/src/coverlet.core/CoverageSummary.cs b/src/coverlet.core/CoverageSummary.cs index 5a64e0b93..188e204d5 100644 --- a/src/coverlet.core/CoverageSummary.cs +++ b/src/coverlet.core/CoverageSummary.cs @@ -73,6 +73,40 @@ public CoverageDetails CalculateBranchCoverage(IList branches) return details; } + public int CalculateNpathComplexity(IList branches) + { + // Adapted from OpenCover see https://github.com/OpenCover/opencover/blob/master/main/OpenCover.Framework/Persistance/BasePersistance.cs#L419 + if (!branches.Any()) + { + return 0; + } + + var paths = new Dictionary(); + foreach (var branch in branches) + { + if (!paths.TryGetValue(branch.Offset, out int count)) + { + count = 0; + } + paths[branch.Offset] = ++count; + } + + int npath = 1; + foreach (var branchPoints in paths.Values) + { + try + { + npath = checked(npath * branchPoints); + } + catch (OverflowException) + { + npath = int.MaxValue; + break; + } + } + return npath; + } + public int CalculateCyclomaticComplexity(IList branches) { return Math.Max(1, branches.Count); diff --git a/src/coverlet.core/Reporters/OpenCoverReporter.cs b/src/coverlet.core/Reporters/OpenCoverReporter.cs index 3c4c66b45..c4135d7a0 100644 --- a/src/coverlet.core/Reporters/OpenCoverReporter.cs +++ b/src/coverlet.core/Reporters/OpenCoverReporter.cs @@ -71,11 +71,12 @@ public string Report(CoverageResult result) 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); XElement method = new XElement("Method"); method.Add(new XAttribute("cyclomaticComplexity", methCyclomaticComplexity.ToString())); - method.Add(new XAttribute("nPathComplexity", "0")); + method.Add(new XAttribute("nPathComplexity", methCyclomaticComplexity.ToString())); method.Add(new XAttribute("sequenceCoverage", methLineCoverage.Percent.ToString("G", CultureInfo.InvariantCulture))); method.Add(new XAttribute("branchCoverage", methBranchCoverage.Percent.ToString("G", CultureInfo.InvariantCulture))); method.Add(new XAttribute("isConstructor", meth.Key.Contains("ctor").ToString())); diff --git a/test/coverlet.core.tests/Reporters/OpenCoverReporterTests.cs b/test/coverlet.core.tests/Reporters/OpenCoverReporterTests.cs index f614d72b4..ee4a90b5a 100644 --- a/test/coverlet.core.tests/Reporters/OpenCoverReporterTests.cs +++ b/test/coverlet.core.tests/Reporters/OpenCoverReporterTests.cs @@ -24,6 +24,7 @@ public void TestReport() XDocument doc = XDocument.Load(new MemoryStream(Encoding.UTF8.GetBytes(report))); Assert.Empty(doc.Descendants().Attributes("sequenceCoverage").Where(v => v.Value != "33.33")); Assert.Empty(doc.Descendants().Attributes("branchCoverage").Where(v => v.Value != "25")); + Assert.Empty(doc.Descendants().Attributes("nPathComplexity").Where(v => v.Value != "4")); } [Fact]