public static CoverturaReport ReadReport(AbsolutePath path) { var doc = XDocument.Load(path); var report = new CoverturaReport(); // get coverage element var coverage = doc.Descendants("coverage").First(); report.LineRate = decimal.Parse(coverage.Attribute("line-rate").Value); report.BranchRate = decimal.Parse(coverage.Attribute("branch-rate").Value); report.LinesCovered = int.Parse(coverage.Attribute("lines-covered").Value); report.LinesValid = int.Parse(coverage.Attribute("lines-valid").Value); report.BranchesCovered = int.Parse(coverage.Attribute("branches-covered").Value); report.BranchesValid = int.Parse(coverage.Attribute("branches-valid").Value); report.Complexity = int.Parse(coverage.Attribute("complexity").Value); report.Packages = coverage .Descendants("packages") .SelectMany(x => x.Descendants("package")) .Select(packageEle => new CoverturaReport.Package { Name = packageEle.Attribute("name").Value, LineRate = decimal.Parse(packageEle.Attribute("line-rate").Value), BranchRate = decimal.Parse(packageEle.Attribute("branch-rate").Value), Complexity = int.Parse(packageEle.Attribute("complexity").Value), Classes = packageEle .Descendants("classes") .SelectMany(x => x.Descendants("class")) .Select(classEle => { var lineHits = classEle.Descendants("lines") .First() .Descendants("line") .Select(x => int.Parse(x.Attribute("hits").Value) > 0) .ToList(); return(new CoverturaReport.ClassDetails() { Name = classEle.Attribute("name").Value, Filename = classEle.Attribute("filename").Value, LineRate = decimal.Parse(classEle.Attribute("line-rate").Value), BranchRate = decimal.Parse(classEle.Attribute("branch-rate").Value), Complexity = int.Parse(classEle.Attribute("complexity").Value), LinesCovered = lineHits.Count, LinesValid = lineHits.Count(x => x), }); }) .ToDictionary(x => $"{x.Filename}_{x.Name}", x => x), }) .ToDictionary(x => x.Name, x => x); return(report); }
public static CoverturaReportComparison Compare(CoverturaReport oldReport, CoverturaReport newReport) { var comparison = new CoverturaReportComparison { Old = oldReport, New = newReport, LineCoverageChange = decimal.Round(newReport.LineRate - oldReport.LineRate, decimals: 2), BranchCoverageChange = decimal.Round(newReport.BranchRate - oldReport.BranchRate, decimals: 2), ComplexityChange = newReport.Complexity - oldReport.Complexity, }; var matchedPackages = new Dictionary <string, CoverturaReportComparison.PackageChanges>(); foreach (var kvp in oldReport.Packages) { var oldPackage = kvp.Value; // try and find package in other report if (!newReport.Packages.TryGetValue(kvp.Key, out var newPackage)) { // package was removed comparison.RemovedPackages.Add(oldPackage); continue; } // do class-level comparison var changes = new CoverturaReportComparison.PackageChanges { Old = oldPackage, New = newPackage, LineCoverageChange = decimal.Round(newPackage.LineRate - oldPackage.LineRate, decimals: 2), BranchCoverageChange = decimal.Round(newPackage.BranchRate - oldPackage.BranchRate, decimals: 2), ComplexityChange = newPackage.Complexity - oldPackage.Complexity, }; foreach (var classKvp in oldPackage.Classes) { var oldClass = classKvp.Value; if (!newPackage.Classes.TryGetValue(classKvp.Key, out var newClass)) { changes.RemovedClasses.Add(oldClass); continue; } var changeSummary = new CoverturaReportComparison.ClassChanges { Name = oldClass.Name, Filename = oldClass.Filename, LineCoverageChange = decimal.Round(newClass.LineRate - oldClass.LineRate, decimals: 2), BranchCoverageChange = decimal.Round(newClass.BranchRate - oldClass.BranchRate, decimals: 2), ComplexityChange = newClass.Complexity - oldClass.Complexity, }; changeSummary.IsSignificantChange = Math.Abs(changeSummary.LineCoverageChange) > SignificantChangeThreshold || Math.Abs(changeSummary.BranchCoverageChange) > SignificantChangeThreshold; changes.ClassChanges[classKvp.Key] = changeSummary; } changes.NewClasses = newPackage.Classes .Where(kvp => !oldPackage.Classes.ContainsKey(kvp.Key)) .Select(kvp => kvp.Value) .ToList(); matchedPackages.Add(kvp.Key, changes); } comparison.MatchedPackages = matchedPackages.Values.ToList(); comparison.NewPackages = newReport.Packages .Where(kvp => !matchedPackages.ContainsKey(kvp.Key)) .Select(kvp => kvp.Value) .ToList(); return(comparison); }