Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 100 additions & 52 deletions src/coverlet.core/Reporters/CoberturaReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace Coverlet.Core.Reporters
{
Expand All @@ -16,94 +18,140 @@ public string Report(CoverageResult result)
{
CoverageSummary summary = new CoverageSummary();

XmlDocument xml = new XmlDocument();
XmlElement coverage = xml.CreateElement("coverage");
coverage.SetAttribute("line-rate", summary.CalculateLineCoverage(result.Modules).ToString());
coverage.SetAttribute("branch-rate", summary.CalculateBranchCoverage(result.Modules).ToString());
coverage.SetAttribute("version", "1.9");
coverage.SetAttribute("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString());
int totalLines = 0, coveredLines = 0, totalBranches = 0, coveredBranches = 0;

XmlElement sources = xml.CreateElement("sources");
foreach (var src in GetSources(result.Modules))
{
XmlElement source = xml.CreateElement("source");
source.AppendChild(xml.CreateTextNode(src));
sources.AppendChild(source);
}
XDocument xml = new XDocument();
XElement coverage = new XElement("coverage");
coverage.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(result.Modules).ToString()));
coverage.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(result.Modules).ToString()));
coverage.Add(new XAttribute("version", "1.9"));
coverage.Add(new XAttribute("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString()));

XElement sources = new XElement("sources");
var basePath = GetBasePath(result.Modules);
sources.Add(new XElement("source", basePath));

XmlElement packages = xml.CreateElement("packages");
XElement packages = new XElement("packages");
foreach (var module in result.Modules)
{
XmlElement package = xml.CreateElement("package");
package.SetAttribute("line-rate", summary.CalculateLineCoverage(module.Value).ToString());
package.SetAttribute("branch-rate", summary.CalculateBranchCoverage(module.Value).ToString());
package.SetAttribute("complexity", "0");
XElement package = new XElement("package");
package.Add(new XAttribute("name", Path.GetFileNameWithoutExtension(module.Key)));
package.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(module.Value).ToString()));
package.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(module.Value).ToString()));
package.Add(new XAttribute("complexity", "0"));

XmlElement classes = xml.CreateElement("classes");
XElement classes = new XElement("classes");
foreach (var document in module.Value)
{
foreach (var cls in document.Value)
{
XmlElement @class = xml.CreateElement("class");
@class.SetAttribute("name", cls.Key);
@class.SetAttribute("filename", Path.GetFileName(document.Key));
@class.SetAttribute("line-rate", summary.CalculateLineCoverage(cls.Value).ToString());
@class.SetAttribute("branch-rate", summary.CalculateBranchCoverage(cls.Value).ToString());
@class.SetAttribute("complexity", "0");

XmlElement methods = xml.CreateElement("methods");
XElement @class = new XElement("class");
@class.Add(new XAttribute("name", cls.Key));
@class.Add(new XAttribute("filename", GetRelativePathFromBase(basePath, document.Key)));
@class.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(cls.Value).ToString()));
@class.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(cls.Value).ToString()));
@class.Add(new XAttribute("complexity", "0"));

XElement classLines = new XElement("lines");
XElement methods = new XElement("methods");

foreach (var meth in cls.Value)
{
XmlElement method = xml.CreateElement("method");
method.SetAttribute("name", meth.Key.Split(':')[2].Split('(')[0]);
method.SetAttribute("signature", meth.Key);
method.SetAttribute("line-rate", summary.CalculateLineCoverage(meth.Value).ToString());
method.SetAttribute("branch-rate", summary.CalculateBranchCoverage(meth.Value).ToString());
XElement method = new XElement("method");
method.Add(new XAttribute("name", meth.Key.Split(':')[2].Split('(')[0]));
method.Add(new XAttribute("signature", "(" + meth.Key.Split(':')[2].Split('(')[1]));
method.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(meth.Value).ToString()));
method.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(meth.Value).ToString()));

XmlElement lines = xml.CreateElement("lines");
XElement lines = new XElement("lines");
foreach (var ln in meth.Value)
{
XmlElement line = xml.CreateElement("line");
line.SetAttribute("number", ln.Key.ToString());
line.SetAttribute("hits", ln.Value.Hits.ToString());
line.SetAttribute("branch", ln.Value.IsBranchPoint.ToString());
XElement line = new XElement("line");
line.Add(new XAttribute("number", ln.Key.ToString()));
line.Add(new XAttribute("hits", ln.Value.Hits.ToString()));
line.Add(new XAttribute("branch", ln.Value.IsBranchPoint.ToString()));

totalLines++;
if (ln.Value.Hits > 0) coveredLines++;


if (ln.Value.IsBranchPoint)
{
line.Add(new XAttribute("condition-coverage", "100% (1/1)"));
XElement conditions = new XElement("conditions");
XElement condition = new XElement("condition");
condition.Add(new XAttribute("number", "0"));
condition.Add(new XAttribute("type", "jump"));
condition.Add(new XAttribute("coverage", "100%"));

totalBranches++;
if (ln.Value.Hits > 0) coveredBranches++;

conditions.Add(condition);
line.Add(conditions);
}

lines.AppendChild(line);

lines.Add(line);
classLines.Add(line);
}

method.AppendChild(lines);
methods.AppendChild(method);
method.Add(lines);
methods.Add(method);
}

@class.AppendChild(methods);
classes.AppendChild(@class);
@class.Add(methods);
@class.Add(classLines);
classes.Add(@class);
}
}

package.AppendChild(classes);
packages.AppendChild(package);
package.Add(classes);
packages.Add(package);
}

coverage.AppendChild(sources);
coverage.AppendChild(packages);
xml.AppendChild(coverage);
coverage.Add(new XAttribute("lines-covered", coveredLines.ToString()));
coverage.Add(new XAttribute("lines-valid", totalLines.ToString()));
coverage.Add(new XAttribute("branches-covered", coveredBranches.ToString()));
coverage.Add(new XAttribute("branches-valid", totalBranches.ToString()));

coverage.Add(sources);
coverage.Add(packages);
xml.Add(coverage);

StringWriter writer = new StringWriter();
xml.Save(writer);
var stream = new MemoryStream();
xml.Save(stream);

return writer.ToString();
return Encoding.UTF8.GetString(stream.ToArray());
}

private string[] GetSources(Modules modules)
private string GetBasePath(Modules modules)
{
List<string> sources = new List<string>();
string source = string.Empty;

foreach (var module in modules)
{
sources.AddRange(
module.Value.Select(d => Path.GetDirectoryName(d.Key)));
}

return sources.Distinct().ToArray();
sources = sources.Distinct().ToList();
var segments = sources[0].Split(Path.DirectorySeparatorChar);

foreach (var segment in segments)
{
var startsWith = sources.All(s => s.StartsWith(source + segment));
if (!startsWith)
break;

source += segment + Path.DirectorySeparatorChar;
}

return source;
}

private string GetRelativePathFromBase(string source, string path)
=> path.Replace(source, string.Empty);
}
}
2 changes: 1 addition & 1 deletion src/coverlet.core/Reporters/LcovReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public string Report(CoverageResult result)
{
foreach (var line in method.Value)
{
lcov.Add($"DA:{line.Key},{line.Value}");
lcov.Add($"DA:{line.Key},{line.Value.Hits}");
}
}
}
Expand Down
Loading