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

Branch Enhancements (take 2) #73

Merged

Conversation

hunterjm
Copy link
Contributor

@hunterjm hunterjm commented May 2, 2018

Description

This PR covers a lot of changes in order to better support branch coverage. The main purpose of this refactor is two-fold. First, to add improved support for branch coverage. Second, to improve the output of the 3 supported report formats by adding previously missing information.

At a high level, this PR covers the objectives by:

  • Resolving Enhanced Branch Coverage #67.
    • Updated all report generators with new branch logic.
  • Changing Coverage Calculation from average of averages to a single average of the sums of covered/total points (for line, branch, and method).
    • Utilized the new CoverageDetails result model from CoverageSummary in report generators in lieu of manually tracking and incrementing visits and counts.

Note

I re-forked and re-applied the changed from #69 because I managed to royally screw up the git history in that fork. What that means is I've effectively squashed all those commits into one, so you don't get to see my fun debugging journey, and for that - I'm sorry.

@tonerdo
Copy link
Collaborator

tonerdo commented May 2, 2018

No worries. Will take a look later today

Copy link
Collaborator

@tonerdo tonerdo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking the time out to work on this in detail. Just a couple of changes and we are good to go. This is going into the 2.0 release because of the breaking changes in the json format

@@ -4,149 +4,232 @@

namespace Coverlet.Core
{
public class CoverageDetails
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to its own file CoverageDetails.cs

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also make Covered and Total internal set

{
public double Covered { get; set; }
public int Total { get; set; }
public double Percent { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only be "gettable". Do the percent calculation in the get{} block

details.Covered = lines.Where(l => l.Value.Hits > 0).Count();
details.Total = lines.Count;
double coverage = details.Total == 0 ? details.Total : details.Covered / details.Total;
details.Percent = Math.Round(coverage, 3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this an all other Percent calculations to the get block of this property

index += 3;
}

if (targetedBranchPoints.Count() > 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't seem to be a reason to check the count here. If it's empty the next loop simply won't run

@@ -143,8 +171,8 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor
document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName });
}

string flag = IsBranchTarget(processor, instruction) ? "B" : "L";
string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine},{flag}";
// string flag = branchPoints.Count > 0 ? "B" : "L";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this line

public static class CecilSymbolHelper
{
private const int StepOverLineCode = 0xFEEFEE;
private static readonly Regex IsMovenext = new Regex(@"\<[^\s>]+\>\w__\w(\w)?::MoveNext\(\)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of text that'll match this pattern

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Empty line after this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
catch (Exception ex)
{
throw new InvalidOperationException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a sane fallback instead of throwing an exception.

Copy link
Contributor Author

@hunterjm hunterjm May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only change I haven't yet made from this review. Do you have any suggestions? It's just catching any other exception that gets thrown and giving it a more descriptive message. This was pulled directly from OpenCover's CecilSymbolManager.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps put the try...catch inside the loop and simply continue to ignore the error. I don't see much point throwing an exception because the developer most likely won't know what/how to fix it. IMO better to have some missing coverage info than to have the entire thing fail with no directions on how to fix it. Also if this file was pulled from OpenCover I think it'll be right to attribute it to the project

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first 4 lines of this file include that attribution.

var branchingInstructionLine = closestSeqPt.Maybe(x => x.StartLine, -1);
var document = closestSeqPt.Maybe(x => x.Document.Url);

if (null == instruction.Next)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: instruction.Next == null

GetBranchPoints(methodDefinition, list);
return list;
}
private static void GetBranchPoints(MethodDefinition methodDefinition, List<BranchPoint> list)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just make this method signature public static List<BranchPoint> GetBranchPoints(MethodDefinition methodDefinition) and initialize the BranchPoint list in it

Copy link
Contributor Author

@hunterjm hunterjm May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reduces the number of times we have to return the list if we need to short circuit the method. Other than that, it's the structure that existed in OpenCover: https://github.com/OpenCover/opencover/blob/master/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs#L351

I can still change it if you'd like.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll appreciate if you change it, thanks

@hunterjm
Copy link
Contributor Author

hunterjm commented May 5, 2018

All requested changes completed.

@tonerdo tonerdo merged commit 2597da9 into coverlet-coverage:master May 5, 2018
@hunterjm hunterjm deleted the feature/branchEnhancements branch May 5, 2018 18:01
NorekZ pushed a commit to NorekZ/coverlet that referenced this pull request Nov 8, 2018
…nhancements

Branch Enhancements (take 2)
mburumaxwell pushed a commit to faluapp/falu-dotnet that referenced this pull request Jun 12, 2021
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 1.3.0 to 3.0.1.

#Release notes

*Sourced from [coverlet.collector's releases](https://github.com/coverlet-coverage/coverlet/releases).*

> ## v3.0.0
> * [#131](coverlet-coverage/coverlet#131) makes a slight change to the Coverlet JSON format
> * 807f7b1bd5bea8158ffff343d5511cd16e0da9a0 uses a separate `coverlet.tracker` assembly to hold tracking code
> * [#128](coverlet-coverage/coverlet#128) adds support for assemblies with `.exe` extension
> * a1f18b4156374f3398d704e898ec58c7c6c64bf8 improves identifying compiler generated types
> * [#134](coverlet-coverage/coverlet#134) adds considerable coverage tracking performance improvements
>
> ## v2.0.1
> * [#102](coverlet-coverage/coverlet#102) fixes issues with NUNIT3 Test adapter ([#101](coverlet-coverage/coverlet#101))
> * [#104](coverlet-coverage/coverlet#104) shows overall averages as part of final console output
> * [#112](coverlet-coverage/coverlet#112) adds support for standard `ExcludeFromCodeCoverage` attribute to specify types and methods to exclude from code coverage. Deprecates `ExcludeFromCoverage` attribute
> * coverlet-coverage/coverlet@7f190e4 prevents Opencover and Cobertura output generated at the same time from overwriting each other ([#111](coverlet-coverage/coverlet#111))
> * [#116](coverlet-coverage/coverlet#116) strongly signs the Coverlet assembly and aims to fix [#40](coverlet-coverage/coverlet#40)
>
> ## v2.0.0
> * [#78](coverlet-coverage/coverlet#78) adds support for generating multiple report formats in a single run
> * [#73](coverlet-coverage/coverlet#73) improves branch coverage support and output formats*
> * coverlet-coverage/coverlet@d2effb3 shows method coverage in summary output
> * [#88](coverlet-coverage/coverlet#88) improves disk usage by using gzip compression
> * [#93](coverlet-coverage/coverlet#93) adds `ThresholdType` property that allows you to specify the coverage type to apply the `Threshold` property to
> * coverlet-coverage/coverlet@ebedd70 renames `Exclude` property to `ExcludeByFile`*
> * coverlet-coverage/coverlet@9ed0864 supports using filter expressions to exclude assemblies, namespaces or types. Uses the `Exclude` property*
> * [#99](coverlet-coverage/coverlet#99) adds improvements to evaluation of filter expressions
>
> `*` - Backwards incompatible change

#Commits

- See f...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants