Browse Source

Merge pull request #495 from ddur/CodeCoverageFilter

Code coverage filter
pull/499/head
Matt Ward 11 years ago
parent
commit
ff7b87ee41
  1. 121
      src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs

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

@ -58,6 +58,7 @@ namespace ICSharpCode.CodeCoverage @@ -58,6 +58,7 @@ namespace ICSharpCode.CodeCoverage
public string FileID { get; private set; }
public string FileName { get; private set; }
public string FileNameExt { get; private set; }
public bool IsVisited { get; private set; }
public int CyclomaticComplexity { get; private set; }
public decimal SequenceCoverage { get; private set; }
@ -86,9 +87,14 @@ namespace ICSharpCode.CodeCoverage @@ -86,9 +87,14 @@ namespace ICSharpCode.CodeCoverage
this.FileID = GetFileRef();
this.FileName = String.Empty;
this.FileNameExt = String.Empty;
if (!String.IsNullOrEmpty(this.FileID)) {
if (results != null) {
this.FileName = results.GetFileName(this.FileID);
try {
this.FileNameExt = Path.GetExtension(this.FileName).ToLowerInvariant();
}
catch {}
if (cacheFileName != this.FileName) {
cacheFileName = this.FileName;
cacheDocument = GetSource (cacheFileName);
@ -220,14 +226,19 @@ namespace ICSharpCode.CodeCoverage @@ -220,14 +226,19 @@ namespace ICSharpCode.CodeCoverage
// -> this method SP with lowest Line/Column
void getBodyStartSP() {
if (this.SequencePoints.Count != 0) {
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
if (sp.FileID != this.FileID) continue;
if (this.BodyStartSP == null || (sp.Line < this.BodyStartSP.Line) ||
(sp.Line == this.BodyStartSP.Line && sp.Column < this.BodyStartSP.Column)
) {
this.BodyStartSP = sp;
if (this.FileNameExt == ".cs") {
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
if (sp.FileID != this.FileID) continue;
if (this.BodyStartSP == null || (sp.Line < this.BodyStartSP.Line) ||
(sp.Line == this.BodyStartSP.Line && sp.Column < this.BodyStartSP.Column)
) {
this.BodyStartSP = sp;
}
}
}
else {
this.BodyStartSP = this.SequencePoints.First();
}
}
}
@ -236,29 +247,34 @@ namespace ICSharpCode.CodeCoverage @@ -236,29 +247,34 @@ namespace ICSharpCode.CodeCoverage
// and lowest Offset (when duplicated bw ccrewrite)
void getBodyFinalSP() {
if (this.SequencePoints.Count != 0) {
for (int i = this.SequencePoints.Count-1; i > 0; i--) {
var sp = this.SequencePoints[i];
if (sp.FileID != this.FileID) continue;
if (sp.Content != "}") continue;
if (this.BodyFinalSP == null || (sp.Line > this.BodyFinalSP.Line) ||
(sp.Line == this.BodyFinalSP.Line && sp.Column >= this.BodyFinalSP.Column)
) {
// ccrewrite ContractClass/ContractClassFor
// adds duplicate method end-sequence-point "}"
//
// Take duplicate BodyFinalSP with lower Offset
// Because IL.Offset of second duplicate
// will extend branch coverage of this method
// by coverage of ContractClassFor inserted SequencePoint!
if (this.BodyFinalSP != null &&
sp.Line == this.BodyFinalSP.Line &&
sp.Column == this.BodyFinalSP.Column &&
sp.Offset < this.BodyFinalSP.Offset) {
this.SequencePoints.Remove(this.BodyFinalSP); // remove duplicate
if (this.FileNameExt == ".cs") {
for (int i = this.SequencePoints.Count-1; i > 0; i--) {
var sp = this.SequencePoints[i];
if (sp.FileID != this.FileID) continue;
if (sp.Content != "}") continue;
if (this.BodyFinalSP == null || (sp.Line > this.BodyFinalSP.Line) ||
(sp.Line == this.BodyFinalSP.Line && sp.Column >= this.BodyFinalSP.Column)
) {
// ccrewrite ContractClass/ContractClassFor
// adds duplicate method end-sequence-point "}"
//
// Take duplicate BodyFinalSP with lower Offset
// Because IL.Offset of second duplicate
// will extend branch coverage of this method
// by coverage of ContractClassFor inserted SequencePoint!
if (this.BodyFinalSP != null &&
sp.Line == this.BodyFinalSP.Line &&
sp.Column == this.BodyFinalSP.Column &&
sp.Offset < this.BodyFinalSP.Offset) {
this.SequencePoints.Remove(this.BodyFinalSP); // remove duplicate
}
this.BodyFinalSP = sp;
}
this.BodyFinalSP = sp;
}
}
else {
this.BodyFinalSP = this.SequencePoints.Last();
}
}
}
@ -273,6 +289,9 @@ namespace ICSharpCode.CodeCoverage @@ -273,6 +289,9 @@ namespace ICSharpCode.CodeCoverage
return 0;
}
const string @assert = "Assert";
const string @contract = "Contract";
void GetBranchRatio () {
this.BranchCoverageRatio = null;
@ -295,31 +314,33 @@ namespace ICSharpCode.CodeCoverage @@ -295,31 +314,33 @@ namespace ICSharpCode.CodeCoverage
// SequencePoint is visited and belongs to this method?
if (sp.VisitCount != 0 && sp.FileID == this.FileID) {
// Don't want branch coverage of ccrewrite(n)
// SequencePoint's with offset before and after method body
if (sp.Offset < BodyStartSP.Offset ||
sp.Offset > BodyFinalSP.Offset) {
sp.BranchCoverage = true;
continue; // skip
}
if (this.FileNameExt == ".cs") {
// Only for C#
// 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)
// 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)
// 4) Exclude NUnit Assert(.Throws) class
const string assert = "Assert";
const string contract = "Contract";
if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
sp.Content.StartsWith(assert + ".", StringComparison.Ordinal) ||
sp.Content.StartsWith(assert + " ", StringComparison.Ordinal) ||
sp.Content.StartsWith(contract + ".", StringComparison.Ordinal) ||
sp.Content.StartsWith(contract + " ", StringComparison.Ordinal)
) {
sp.BranchCoverage = true;
continue; // skip
// Don't want branch coverage of ccrewrite(n)
// SequencePoint(s) with offset before and after method body
if (sp.Offset < BodyStartSP.Offset ||
sp.Offset > BodyFinalSP.Offset) {
sp.BranchCoverage = true;
continue; // skip
}
// 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)
// 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)
// 4) Exclude NUnit Assert(.Throws) class
if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
sp.Content.StartsWith(@assert + ".", StringComparison.Ordinal) ||
sp.Content.StartsWith(@assert + " ", StringComparison.Ordinal) ||
sp.Content.StartsWith(@contract + ".", StringComparison.Ordinal) ||
sp.Content.StartsWith(@contract + " ", StringComparison.Ordinal)
) {
sp.BranchCoverage = true;
continue; // skip
}
}
totalBranchCount += sp.BranchExitsCount;

Loading…
Cancel
Save