Browse Source

Merge remote-tracking branch 'origin/4.x'

pull/67/head
Dragan 12 years ago
parent
commit
34ed6848bc
  1. 2
      src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageBranchPoint.cs
  2. 745
      src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs
  3. 2
      src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageStringTextSource.cs

2
src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageBranchPoint.cs

@ -1,5 +1,5 @@
// Copyright (c) https://github.com/ddur // Copyright (c) https://github.com/ddur
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the MIT license
using System; using System;

745
src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs

@ -27,344 +27,409 @@ using System.Xml.Linq;
namespace ICSharpCode.CodeCoverage namespace ICSharpCode.CodeCoverage
{ {
public class CodeCoverageMethodElement public class CodeCoverageMethodElement
{ {
XElement element; XElement element;
CodeCoverageResults parent; CodeCoverageResults parent;
public CodeCoverageMethodElement(XElement element, CodeCoverageResults parent) public CodeCoverageMethodElement(XElement element, CodeCoverageResults parent)
{ {
this.parent = parent; this.parent = parent;
this.element = element; this.element = element;
this.SequencePoints = new List<CodeCoverageSequencePoint>(); this.SequencePoints = new List<CodeCoverageSequencePoint>();
this.BranchPoints = new List<CodeCoverageBranchPoint>(); this.BranchPoints = new List<CodeCoverageBranchPoint>();
Init(); Init();
} }
private static string cacheFileName = String.Empty; private static string cacheFileName = String.Empty;
private static CodeCoverageStringTextSource cacheDocument = null; private static CodeCoverageStringTextSource cacheDocument = null;
public string FileID { get; private set; } public string FileID { get; private set; }
public string FileName { get; private set; } public string FileName { get; private set; }
public bool IsVisited { get; private set; } public bool IsVisited { get; private set; }
public int CyclomaticComplexity { get; private set; } public int CyclomaticComplexity { get; private set; }
public decimal SequenceCoverage { get; private set; } public decimal SequenceCoverage { get; private set; }
public int SequencePointsCount { get; private set; } public int SequencePointsCount { get; private set; }
public decimal BranchCoverage { get; private set; } public decimal BranchCoverage { get; private set; }
public Tuple<int,int> BranchCoverageRatio { get; private set; } public Tuple<int,int> BranchCoverageRatio { get; private set; }
public bool IsConstructor { get; private set; } public bool IsConstructor { get; private set; }
public bool IsStatic { get; private set; } public bool IsStatic { get; private set; }
public List<CodeCoverageSequencePoint> SequencePoints { get; private set; } public List<CodeCoverageSequencePoint> SequencePoints { get; private set; }
public List<CodeCoverageBranchPoint> BranchPoints { get; private set; } public CodeCoverageSequencePoint BodyStartSP { get; private set; }
public CodeCoverageSequencePoint BodyFinalSP { get; private set; }
public bool IsGetter { get; private set; } public List<CodeCoverageBranchPoint> BranchPoints { get; private set; }
public bool IsSetter { get; private set; }
public string MethodName { get; private set; } public bool IsGetter { get; private set; }
public bool IsSetter { get; private set; }
public bool IsProperty { public string MethodName { get; private set; }
get { return IsGetter || IsSetter; }
} public bool IsProperty {
get { return IsGetter || IsSetter; }
void Init() }
{
MethodName = GetMethodName(); void Init()
IsGetter = GetBooleanAttributeValue("isGetter"); {
IsSetter = GetBooleanAttributeValue("isSetter"); MethodName = GetMethodName();
IsGetter = GetBooleanAttributeValue("isGetter");
this.FileID = GetFileRef(); IsSetter = GetBooleanAttributeValue("isSetter");
this.FileName = String.Empty;
if (!String.IsNullOrEmpty(this.FileID)) { this.FileID = GetFileRef();
this.FileName = parent.GetFileName(this.FileID); this.FileName = String.Empty;
if ( File.Exists(this.FileName) ) { if (!String.IsNullOrEmpty(this.FileID)) {
if (cacheFileName != this.FileName) { this.FileName = parent.GetFileName(this.FileID);
cacheFileName = this.FileName; if ( File.Exists(this.FileName) ) {
cacheDocument = null; if (cacheFileName != this.FileName) {
try { cacheFileName = this.FileName;
using (Stream stream = new FileStream(this.FileName, FileMode.Open, FileAccess.Read)) { cacheDocument = null;
try { try {
stream.Position = 0; using (Stream stream = new FileStream(this.FileName, FileMode.Open, FileAccess.Read)) {
string textSource = ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(stream, Encoding.Default); try {
cacheDocument = new CodeCoverageStringTextSource(textSource); stream.Position = 0;
} catch {} string textSource = ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(stream, Encoding.Default);
} cacheDocument = new CodeCoverageStringTextSource(textSource);
} catch {} } catch {}
} }
} } catch {}
} }
}
this.IsVisited = this.GetBooleanAttributeValue("visited"); }
this.CyclomaticComplexity = (int)this.GetDecimalAttributeValue("cyclomaticComplexity");
this.SequencePointsCount = this.GetSequencePointsCount(); this.IsVisited = this.GetBooleanAttributeValue("visited");
this.SequenceCoverage = (int)this.GetDecimalAttributeValue("sequenceCoverage"); this.CyclomaticComplexity = (int)this.GetDecimalAttributeValue("cyclomaticComplexity");
this.IsConstructor = this.GetBooleanAttributeValue("isConstructor"); this.SequencePointsCount = this.GetSequencePointsCount();
this.IsStatic = this.GetBooleanAttributeValue("isStatic"); this.SequenceCoverage = (int)this.GetDecimalAttributeValue("sequenceCoverage");
if ( !String.IsNullOrEmpty( this.FileID ) ) { this.IsConstructor = this.GetBooleanAttributeValue("isConstructor");
this.SequencePoints = this.GetSequencePoints(); this.IsStatic = this.GetBooleanAttributeValue("isStatic");
this.BranchPoints = this.GetBranchPoints(); if ( !String.IsNullOrEmpty( this.FileID ) ) {
this.BranchCoverageRatio = this.GetBranchRatio(); this.SequencePoints = this.GetSequencePoints();
this.BranchCoverage = this.GetBranchCoverage(); this.BodyStartSP = getBodyStartSP(this.SequencePoints);
} this.BodyFinalSP = getBodyFinalSP(this.SequencePoints);
} this.SequencePoints = this.FilterSequencePoints(this.SequencePoints);
this.BranchPoints = this.GetBranchPoints();
List<CodeCoverageSequencePoint> GetSequencePoints() { this.BranchCoverageRatio = this.GetBranchRatio();
this.BranchCoverage = this.GetBranchCoverage();
List<CodeCoverageSequencePoint> sps = new List<CodeCoverageSequencePoint>(); }
var xSPoints = this.element }
.Elements("SequencePoints")
.Elements("SequencePoint"); List<CodeCoverageSequencePoint> GetSequencePoints() {
foreach (XElement xSPoint in xSPoints) { List<CodeCoverageSequencePoint> sps = new List<CodeCoverageSequencePoint>();
CodeCoverageSequencePoint sp = new CodeCoverageSequencePoint(); var xSPoints = this.element
sp.FileID = this.FileID; .Elements("SequencePoints")
sp.Document = this.FileName; .Elements("SequencePoint");
sp.Line = (int)GetDecimalAttributeValue(xSPoint.Attribute("sl"));
sp.EndLine = (int)GetDecimalAttributeValue(xSPoint.Attribute("el")); foreach (XElement xSPoint in xSPoints) {
sp.Column = (int)GetDecimalAttributeValue(xSPoint.Attribute("sc")); CodeCoverageSequencePoint sp = new CodeCoverageSequencePoint();
sp.EndColumn = (int)GetDecimalAttributeValue(xSPoint.Attribute("ec")); sp.FileID = this.FileID;
sp.VisitCount = (int)GetDecimalAttributeValue(xSPoint.Attribute("vc")); sp.Document = this.FileName;
if (cacheFileName == sp.Document && cacheDocument != null) { sp.Line = (int)GetDecimalAttributeValue(xSPoint.Attribute("sl"));
sp.Content = cacheDocument.GetText(sp); sp.EndLine = (int)GetDecimalAttributeValue(xSPoint.Attribute("el"));
if (sp.Line != sp.EndLine) { sp.Column = (int)GetDecimalAttributeValue(xSPoint.Attribute("sc"));
sp.Content = Regex.Replace (sp.Content, @"\s+", " "); sp.EndColumn = (int)GetDecimalAttributeValue(xSPoint.Attribute("ec"));
} sp.VisitCount = (int)GetDecimalAttributeValue(xSPoint.Attribute("vc"));
sp.Length = Regex.Replace (sp.Content, @"\s", "").Length; // ignore white-space for coverage% if (cacheFileName == sp.Document && cacheDocument != null) {
} else { sp.Content = cacheDocument.GetText(sp);
sp.Content = String.Empty; if (sp.Line != sp.EndLine) {
sp.Length = 0; sp.Content = Regex.Replace (sp.Content, @"\s+", " ");
} }
sp.Offset = (int)GetDecimalAttributeValue(xSPoint.Attribute("offset")); sp.Length = Regex.Replace (sp.Content, @"\s", "").Length; // ignore white-space for coverage%
sp.BranchCoverage = true; } else {
sp.Content = String.Empty;
sps.Add(sp); sp.Length = 0;
} }
return sps; sp.Offset = (int)GetDecimalAttributeValue(xSPoint.Attribute("offset"));
} sp.BranchCoverage = true;
int GetSequencePointsCount() { sps.Add(sp);
XElement summary = this.element.Element("Summary"); }
if ( summary != null ) {
XAttribute nsp = summary.Attribute("numSequencePoints"); // SP's are originaly ordered by CIL offset
if ( nsp != null ) { // but ccrewrite can move offset of
return (int)GetDecimalAttributeValue( nsp ); // Contract.Requires before method signature SP (xxx{) and
} // Contract.Ensures after method closing SP (})
} // So sort SP's back by line/column
return 0; sps.OrderBy(item => item.Line).OrderBy(item => item.Column);
} return sps;
}
List<CodeCoverageBranchPoint> GetBranchPoints() {
// get all BranchPoints // Find method-body start SequencePoint "xxxx {"
List<CodeCoverageBranchPoint> bps = new List<CodeCoverageBranchPoint>(); public static CodeCoverageSequencePoint getBodyStartSP(IEnumerable<CodeCoverageSequencePoint> sPoints) {
var xBPoints = this.element CodeCoverageSequencePoint startSeqPoint = null;
.Elements("BranchPoints") bool startFound = false;
.Elements("BranchPoint"); foreach (CodeCoverageSequencePoint sPoint in sPoints) {
foreach (XElement xBPoint in xBPoints) { if ( sPoint.Content == "{") {
CodeCoverageBranchPoint bp = new CodeCoverageBranchPoint(); if (startSeqPoint == null) startSeqPoint = sPoint;
bp.VisitCount = (int)GetDecimalAttributeValue(xBPoint.Attribute("vc")); startFound = true;
bp.Offset = (int)GetDecimalAttributeValue(xBPoint.Attribute("offset")); break;
bp.Path = (int)GetDecimalAttributeValue(xBPoint.Attribute("path")); }
bp.OffsetEnd = (int)GetDecimalAttributeValue(xBPoint.Attribute("offsetend")); startSeqPoint = sPoint;
bps.Add(bp); }
} return startFound == true? startSeqPoint : null;
return bps; }
}
// Find method-body final SequencePoint "}"
// Find method-body start SequencePoint "{" public static CodeCoverageSequencePoint getBodyFinalSP(IEnumerable<CodeCoverageSequencePoint> sps) {
public static CodeCoverageSequencePoint getBodyStartSP(IEnumerable<CodeCoverageSequencePoint> sps) { CodeCoverageSequencePoint finalSeqPoint = null;
CodeCoverageSequencePoint startSeqPoint = null; foreach (CodeCoverageSequencePoint sp in Enumerable.Reverse(sps)) {
foreach (CodeCoverageSequencePoint sp in sps) { if ( sp.Content == "}") {
if ( sp.Content == "{") { if (finalSeqPoint == null) {
startSeqPoint = sp; finalSeqPoint = sp;
break; }
} // check for ccrewrite duplicate
} else if (sp.Line == finalSeqPoint.Line &&
return startSeqPoint; sp.Column == finalSeqPoint.Column &&
} sp.EndLine == finalSeqPoint.EndLine &&
sp.EndColumn == finalSeqPoint.EndColumn &&
// Find method-body final SequencePoint "}" sp.Offset < finalSeqPoint.Offset) {
public static CodeCoverageSequencePoint getBodyFinalSP(IEnumerable<CodeCoverageSequencePoint> sps) { finalSeqPoint = sp;
CodeCoverageSequencePoint finalSeqPoint = null; }
foreach (CodeCoverageSequencePoint sp in Enumerable.Reverse(sps)) { }
if ( sp.Content == "}") { }
finalSeqPoint = sp; return finalSeqPoint;
break; }
}
} List<CodeCoverageSequencePoint> FilterSequencePoints(List<CodeCoverageSequencePoint> sps) {
return finalSeqPoint;
} List<CodeCoverageSequencePoint> returnList = sps;
Tuple<int,int> GetBranchRatio () { if (sps.Count > 2 &&
this.BodyStartSP != null &&
// goal: Get branch ratio and exclude (rewriten) Code Contracts branches this.BodyFinalSP != null ) {
if ( this.BranchPoints == null // After ccrewrite ContractClass/ContractClassFor
|| this.BranchPoints.Count() == 0 // sequence point(s) from another file/class/method
|| this.SequencePoints == null // is inserted into this method sequence points
|| this.SequencePoints.Count == 0 //
) // To remove alien sequence points, all sequence points on lines
{ // before method signature and after end-brackets xxx{} are removed
return null; // If ContractClassFor is in another file but matches this method lines
} // then, afaik, not much can be done to remove inserted alien SP's
List<CodeCoverageSequencePoint> selected = new List<CodeCoverageSequencePoint>();
// This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Requires)
// and '{' branches at static methods foreach (var point in sps) {
CodeCoverageSequencePoint startSeqPoint = getBodyStartSP(this.SequencePoints); if (
if (Object.ReferenceEquals(null, startSeqPoint)) { return null; } (point.Line > BodyStartSP.Line || (point.Line == BodyStartSP.Line && point.Column >= BodyStartSP.Column)) &&
(point.Line < BodyFinalSP.Line || (point.Line == BodyFinalSP.Line && point.Column < BodyFinalSP.Column))
// This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Ensures) ) {
CodeCoverageSequencePoint finalSeqPoint = getBodyFinalSP(this.SequencePoints); selected.Add (point);
if (Object.ReferenceEquals(null, finalSeqPoint)) { return null; } }
// After ccrewrite ContractClass/ContractClassFor
// Connect Sequence & Branches // duplicate method end-sequence-point (}) is added
IEnumerator<CodeCoverageSequencePoint> SPEnumerator = this.SequencePoints.GetEnumerator(); //
CodeCoverageSequencePoint currSeqPoint = startSeqPoint; // Add first finalSP (can be a duplicate)
int nextSeqPointOffset = startSeqPoint.Offset; // Note: IL.Offset of second duplicate finalSP will
// extend branch coverage outside method-end "}",
foreach (var bp in this.BranchPoints) { // and that can lead to wrong branch coverage display!
if (object.ReferenceEquals (point, this.BodyFinalSP)) {
// ignore branches outside of method body selected.Add (point);
if (bp.Offset < startSeqPoint.Offset) }
continue; }
if (bp.Offset > finalSeqPoint.Offset)
break; returnList = selected;
}
// Sync with SequencePoint
while ( nextSeqPointOffset < bp.Offset ) { return returnList;
currSeqPoint = SPEnumerator.Current; }
if ( SPEnumerator.MoveNext() ) {
nextSeqPointOffset = SPEnumerator.Current.Offset; int GetSequencePointsCount() {
} else { XElement summary = this.element.Element("Summary");
nextSeqPointOffset = int.MaxValue; if ( summary != null ) {
} XAttribute nsp = summary.Attribute("numSequencePoints");
} if ( nsp != null ) {
if (currSeqPoint.Branches == null) { return (int)GetDecimalAttributeValue( nsp );
currSeqPoint.Branches = new List<CodeCoverageBranchPoint>(); }
} }
// Add Branch to Branches return 0;
currSeqPoint.Branches.Add(bp); }
}
List<CodeCoverageBranchPoint> GetBranchPoints() {
// Merge sp.Branches on exit-offset // get all BranchPoints
// Calculate Method Branch coverage List<CodeCoverageBranchPoint> bps = new List<CodeCoverageBranchPoint>();
int totalBranchVisit = 0; var xBPoints = this.element
int totalBranchCount = 0; .Elements("BranchPoints")
int pointBranchVisit = 0; .Elements("BranchPoint");
int pointBranchCount = 0; foreach (XElement xBPoint in xBPoints) {
Dictionary<int, CodeCoverageBranchPoint> bpExits = new Dictionary<int, CodeCoverageBranchPoint>(); CodeCoverageBranchPoint bp = new CodeCoverageBranchPoint();
foreach (var sp in this.SequencePoints) { bp.VisitCount = (int)GetDecimalAttributeValue(xBPoint.Attribute("vc"));
bp.Offset = (int)GetDecimalAttributeValue(xBPoint.Attribute("offset"));
// SequencePoint covered & has branches? bp.Path = (int)GetDecimalAttributeValue(xBPoint.Attribute("path"));
if (sp.VisitCount != 0 && sp.Branches != null) { bp.OffsetEnd = (int)GetDecimalAttributeValue(xBPoint.Attribute("offsetend"));
bps.Add(bp);
// 1) Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that }
// one do not want or cannot cover by test-case because is handled earlier at same method. return bps;
// ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null) }
// 2) Branches within sequence points "{" and "}" are not source branches but compiler generated branches
// ie: static methods start sequence point "{" contains compiler generated branches Tuple<int,int> GetBranchRatio () {
// 3) Exclude Contract class (EnsuresOnThrow/Assert/Assume is inside method body)
// 4) Exclude NUnit Assert(.Throws) class // goal: Get branch ratio and exclude (rewriten) Code Contracts branches
if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
sp.Content.StartsWith("Assert.") || if ( this.BranchPoints == null
sp.Content.StartsWith("Assert ") || || this.BranchPoints.Count() == 0
sp.Content.StartsWith("Contract.") || || this.SequencePoints == null
sp.Content.StartsWith("Contract ") || this.SequencePoints.Count == 0
) { )
sp.Branches = null; {
continue; // skip return null;
} }
// Merge sp.Branches on OffsetEnd using bpExits key // This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Requires)
bpExits.Clear(); // and '{' branches at static methods
foreach (var bp in sp.Branches) { if (this.BodyStartSP == null) { return null; } // empty body
if (!bpExits.ContainsKey(bp.OffsetEnd)) {
bpExits[bp.OffsetEnd] = bp; // insert branch // This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Ensures)
} else { if (this.BodyFinalSP == null) { return null; } // empty body
bpExits[bp.OffsetEnd].VisitCount += bp.VisitCount; // update branch
} // Connect Sequence & Branches
} IEnumerator<CodeCoverageSequencePoint> SPEnumerator = this.SequencePoints.GetEnumerator();
CodeCoverageSequencePoint currSeqPoint = BodyStartSP;
// Compute branch coverage int nextSeqPointOffset = BodyStartSP.Offset;
pointBranchVisit = 0;
pointBranchCount = 0; foreach (var bp in this.BranchPoints) {
foreach (var bp in bpExits.Values) {
pointBranchVisit += bp.VisitCount == 0? 0 : 1 ; // ignore branches outside of method body offset range
pointBranchCount += 1; if (bp.Offset < BodyStartSP.Offset)
} continue;
// Not full coverage? if (bp.Offset > BodyFinalSP.Offset)
if (pointBranchVisit != pointBranchCount) { break;
sp.BranchCoverage = false; // => part-covered
} // Sync with SequencePoint
totalBranchVisit += pointBranchVisit; while ( nextSeqPointOffset < bp.Offset ) {
totalBranchCount += pointBranchCount; currSeqPoint = SPEnumerator.Current;
} if ( SPEnumerator.MoveNext() ) {
if (sp.Branches != null) nextSeqPointOffset = SPEnumerator.Current.Offset;
sp.Branches = null; // release memory } else {
} nextSeqPointOffset = int.MaxValue;
}
return (totalBranchCount!=0) ? new Tuple<int,int>(totalBranchVisit,totalBranchCount) : null; }
if (currSeqPoint.Branches == null) {
} currSeqPoint.Branches = new List<CodeCoverageBranchPoint>();
}
decimal GetBranchCoverage () { // Add Branch to Branches
currSeqPoint.Branches.Add(bp);
return this.BranchCoverageRatio == null ? 0m : ((decimal)(this.BranchCoverageRatio.Item1*100))/((decimal)this.BranchCoverageRatio.Item2); }
} // Merge sp.Branches on exit-offset
// Calculate Method Branch coverage
decimal GetDecimalAttributeValue(string name) int totalBranchVisit = 0;
{ int totalBranchCount = 0;
return GetDecimalAttributeValue(element.Attribute(name)); int pointBranchVisit = 0;
} int pointBranchCount = 0;
Dictionary<int, CodeCoverageBranchPoint> bpExits = new Dictionary<int, CodeCoverageBranchPoint>();
decimal GetDecimalAttributeValue(XAttribute attribute) foreach (var sp in this.SequencePoints) {
{
if (attribute != null) { // SequencePoint covered & has branches?
decimal value = 0; if (sp.VisitCount != 0 && sp.Branches != null) {
if (Decimal.TryParse(attribute.Value, out value)) {
return value; // 1) Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that
} // one do not want or cannot cover by test-case because is handled earlier at same method.
} // ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null)
return 0; // 2) Branches within sequence points "{" and "}" are not source branches but compiler generated branches
} // ie: static methods start sequence point "{" contains compiler generated branches
// 3) Exclude Contract class (EnsuresOnThrow/Assert/Assume is inside method body)
bool GetBooleanAttributeValue(string name) // 4) Exclude NUnit Assert(.Throws) class
{ if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
return GetBooleanAttributeValue(element.Attribute(name)); sp.Content.StartsWith("Assert.") ||
} sp.Content.StartsWith("Assert ") ||
sp.Content.StartsWith("Contract.") ||
bool GetBooleanAttributeValue(XAttribute attribute) sp.Content.StartsWith("Contract ")
{ ) {
if (attribute != null) { sp.Branches = null;
bool value = false; continue; // skip
if (Boolean.TryParse(attribute.Value, out value)) { }
return value;
} // Merge sp.Branches on OffsetEnd using bpExits key
} bpExits.Clear();
return false; foreach (var bp in sp.Branches) {
} if (!bpExits.ContainsKey(bp.OffsetEnd)) {
bpExits[bp.OffsetEnd] = bp; // insert branch
string GetFileRef() { } else {
XElement fileId = element.Element("FileRef"); bpExits[bp.OffsetEnd].VisitCount += bp.VisitCount; // update branch
if (fileId != null) { }
return fileId.Attribute("uid").Value; }
}
return String.Empty; // Compute branch coverage
} pointBranchVisit = 0;
pointBranchCount = 0;
string GetMethodName() foreach (var bp in bpExits.Values) {
{ pointBranchVisit += bp.VisitCount == 0? 0 : 1 ;
XElement nameElement = element.Element("Name"); pointBranchCount += 1;
if (nameElement != null) { }
return GetMethodName(nameElement.Value); // Not full coverage?
} if (pointBranchVisit != pointBranchCount) {
return String.Empty; sp.BranchCoverage = false; // => part-covered
} }
totalBranchVisit += pointBranchVisit;
string GetMethodName(string methodSignature) totalBranchCount += pointBranchCount;
{ }
int startIndex = methodSignature.IndexOf("::"); if (sp.Branches != null)
int endIndex = methodSignature.IndexOf('(', startIndex); sp.Branches = null; // release memory
return methodSignature }
.Substring(startIndex, endIndex - startIndex)
.Substring(2); return (totalBranchCount!=0) ? new Tuple<int,int>(totalBranchVisit,totalBranchCount) : null;
}
} }
decimal GetBranchCoverage () {
return this.BranchCoverageRatio == null ? 0m : ((decimal)(this.BranchCoverageRatio.Item1*100))/((decimal)this.BranchCoverageRatio.Item2);
}
decimal GetDecimalAttributeValue(string name)
{
return GetDecimalAttributeValue(element.Attribute(name));
}
decimal GetDecimalAttributeValue(XAttribute attribute)
{
if (attribute != null) {
decimal value = 0;
if (Decimal.TryParse(attribute.Value, out value)) {
return value;
}
}
return 0;
}
bool GetBooleanAttributeValue(string name)
{
return GetBooleanAttributeValue(element.Attribute(name));
}
bool GetBooleanAttributeValue(XAttribute attribute)
{
if (attribute != null) {
bool value = false;
if (Boolean.TryParse(attribute.Value, out value)) {
return value;
}
}
return false;
}
string GetFileRef() {
XElement fileId = element.Element("FileRef");
if (fileId != null) {
return fileId.Attribute("uid").Value;
}
return String.Empty;
}
string GetMethodName()
{
XElement nameElement = element.Element("Name");
if (nameElement != null) {
return GetMethodName(nameElement.Value);
}
return String.Empty;
}
string GetMethodName(string methodSignature)
{
int startIndex = methodSignature.IndexOf("::");
int endIndex = methodSignature.IndexOf('(', startIndex);
return methodSignature
.Substring(startIndex, endIndex - startIndex)
.Substring(2);
}
}
} }

2
src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageStringTextSource.cs

@ -1,5 +1,5 @@
// Copyright (c) https://github.com/ddur // Copyright (c) https://github.com/ddur
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under MIT license
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

Loading…
Cancel
Save