Skip to content

Commit

Permalink
TestEngine: Compute coverage branches (#936)
Browse files Browse the repository at this point in the history
* Compute coverage branches

* fix ut

* format

* Reduce changes
  • Loading branch information
shargon authored Feb 22, 2024
1 parent 1c030a0 commit 8804b4a
Show file tree
Hide file tree
Showing 10 changed files with 452 additions and 140 deletions.
91 changes: 68 additions & 23 deletions src/Neo.SmartContract.Testing/Coverage/CoverageBase.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,89 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Neo.SmartContract.Testing.Coverage
{
public abstract class CoverageBase : IEnumerable<CoverageHit>
public abstract class CoverageBase
{
/// <summary>
/// Coverage
/// Coverage Branches
/// </summary>
public abstract IEnumerable<CoverageHit> Coverage { get; }
public abstract IEnumerable<CoverageBranch> Branches { get; }

/// <summary>
/// Total instructions (could be different from Coverage.Count if, for example, a contract JUMPS to PUSHDATA content)
/// Coverage Lines
/// </summary>
public virtual int TotalInstructions => Coverage.Where(u => !u.OutOfScript).Count();
public abstract IEnumerable<CoverageHit> Lines { get; }

/// <summary>
/// Covered Instructions (OutOfScript are not taken into account)
/// Total lines instructions (could be different from Coverage.Count if, for example, a contract JUMPS to PUSHDATA content)
/// </summary>
public virtual int CoveredInstructions => Coverage.Where(u => !u.OutOfScript && u.Hits > 0).Count();
public int TotalLines => Lines.Where(u => !u.OutOfScript).Count();

/// <summary>
/// All instructions that have been touched
/// Total branches
/// </summary>
public virtual int HitsInstructions => Coverage.Where(u => u.Hits > 0).Count();
public int TotalBranches => Branches.Where(u => !u.OutOfScript).Sum(u => u.Count);

/// <summary>
/// Covered Percentage
/// Covered lines (OutOfScript are not taken into account)
/// </summary>
public float CoveredPercentage
public int CoveredLines => Lines.Where(u => !u.OutOfScript && u.Hits > 0).Count();

/// <summary>
/// Covered lines (OutOfScript are not taken into account)
/// </summary>
public int CoveredBranches => Branches.Where(u => !u.OutOfScript && u.Hits > 0).Count();

/// <summary>
/// All lines that have been touched
/// </summary>
public int CoveredLinesAll => Lines.Where(u => u.Hits > 0).Count();

/// <summary>
/// All branches that have been touched
/// </summary>
public int CoveredBranchesAll => Branches.Where(u => u.Hits > 0).Count();

/// <summary>
/// Covered lines percentage
/// </summary>
public float CoveredLinesPercentage
{
get
{
var total = TotalLines;
if (total == 0) return 1F;

return (float)CoveredLines / total;
}
}

/// <summary>
/// Covered branch percentage
/// </summary>
public float CoveredBranchPercentage
{
get
{
var total = TotalInstructions;
if (total == 0) return 0F;
var total = TotalBranches;
if (total == 0) return 1F;

return (float)CoveredInstructions / total;
return (float)CoveredBranches / total;
}
}

/// <summary>
/// Get Coverage from the Contract coverage
/// Get Coverage lines from the Contract coverage
/// </summary>
/// <param name="offset">Offset</param>
/// <param name="length">Length</param>
/// <returns>Coverage</returns>
public IEnumerable<CoverageHit> GetCoverageFrom(int offset, int length)
public IEnumerable<CoverageHit> GetCoverageLinesFrom(int offset, int length)
{
var to = offset + length;

foreach (var kvp in Coverage)
foreach (var kvp in Lines)
{
if (kvp.Offset >= offset && kvp.Offset <= to)
{
Expand All @@ -59,12 +92,24 @@ public IEnumerable<CoverageHit> GetCoverageFrom(int offset, int length)
}
}

#region IEnumerable

public IEnumerator<CoverageHit> GetEnumerator() => Coverage.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Coverage.GetEnumerator();
/// <summary>
/// Get Coverage branch from the Contract coverage
/// </summary>
/// <param name="offset">Offset</param>
/// <param name="length">Length</param>
/// <returns>Coverage</returns>
public IEnumerable<CoverageBranch> GetCoverageBranchFrom(int offset, int length)
{
var to = offset + length;

#endregion
foreach (var kvp in Branches)
{
if (kvp.Offset >= offset && kvp.Offset <= to)
{
yield return kvp;
}
}
}

// Allow to sum coverages

Expand Down
84 changes: 84 additions & 0 deletions src/Neo.SmartContract.Testing/Coverage/CoverageBranch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Diagnostics;

namespace Neo.SmartContract.Testing.Coverage
{
[DebuggerDisplay("Offset={Offset}, Count={Count}, Hits={Hits}")]
public class CoverageBranch
{
/// <summary>
/// Offset
/// </summary>
public int Offset { get; }

/// <summary>
/// Count
/// </summary>
public int Count { get; }

/// <summary>
/// The branch is out of the script
/// </summary>
public bool OutOfScript { get; }

/// <summary>
/// Hits
/// </summary>
public int Hits => (PositivePathHits > 0 ? 1 : 0) + (NegativePathHits > 0 ? 1 : 0);

/// <summary>
/// Positive path hits
/// </summary>
public int PositivePathHits { get; set; }

/// <summary>
/// Negative Path hits
/// </summary>
public int NegativePathHits { get; set; }

/// <summary>
/// Constructor
/// </summary>
/// <param name="offset">Offset</param>
/// <param name="outOfScript">Out of script</param>
public CoverageBranch(int offset, bool outOfScript = false)
{
Offset = offset;
Count = 2;
OutOfScript = outOfScript;
}

/// <summary>
/// Hit branch
/// </summary>
/// <param name="value">Value</param>
public void Hit(bool value)
{
if (value) PositivePathHits++;
else NegativePathHits++;
}

/// <summary>
/// Hit branch
/// </summary>
/// <param name="value">Value</param>
public void Hit(CoverageBranch value)
{
PositivePathHits += value.PositivePathHits;
NegativePathHits += value.NegativePathHits;
}

/// <summary>
/// Clone branch
/// </summary>
/// <returns>CoverageBranch</returns>
public CoverageBranch Clone()
{
return new CoverageBranch(Offset, OutOfScript)
{
NegativePathHits = NegativePathHits,
PositivePathHits = PositivePathHits
};
}
}
}
27 changes: 22 additions & 5 deletions src/Neo.SmartContract.Testing/Coverage/CoveredCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,34 @@ public class CoveredCollection : CoverageBase
public CoverageBase[] Entries { get; }

/// <summary>
/// Coverage
/// Coverage Lines
/// </summary>
public override IEnumerable<CoverageHit> Coverage
public override IEnumerable<CoverageHit> Lines
{
get
{
foreach (var method in Entries)
foreach (var entry in Entries)
{
foreach (var entry in method.Coverage)
foreach (var line in entry.Lines)
{
yield return entry;
yield return line;
}
}
}
}

/// <summary>
/// Coverage Branches
/// </summary>
public override IEnumerable<CoverageBranch> Branches
{
get
{
foreach (var entry in Entries)
{
foreach (var branch in entry.Branches)
{
yield return branch;
}
}
}
Expand Down
Loading

0 comments on commit 8804b4a

Please sign in to comment.