Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestEngine: Compute coverage branches #936

Merged
merged 4 commits into from
Feb 22, 2024
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
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
Loading