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

Coverage percentage output value rounded down with max 2 decimal precision #397

Merged
merged 4 commits into from
May 7, 2019
Merged

Coverage percentage output value rounded down with max 2 decimal precision #397

merged 4 commits into from
May 7, 2019

Conversation

sasivishnu
Copy link
Contributor

@sasivishnu sasivishnu commented May 4, 2019

Reports-After_Change.zip
Reports-Before_Change.zip

Related to issue #382

Change Details:

  1. All percentage output are rounded down (Floor) with maximum of 2 decimal precision.
  2. Arithmetic precision error fixed by rounding- ex: 0.1400D * 100 = 14.000000000000002
  3. In Cobertura Report, "line-rate" and "branch-rate" value will have an extra decimal precision
    Before: 0.143
    After: 0.1432
  4. In OpenCover report, "sequenceCoverage" and "branchCoverage" value will have an extra decimal precision
    Before: 33.3
    After: 33.33
  5. In TeamCitry report, "CodeCoverageR" value will have an extra decimal precision
    Before: 33.3
    After: 33.33

I also updated and added new test cases to cover for the changes. Previously, we are rounding with max 3 decimal points before multiplying with 100. This yields value like 81.5%. I had to increase that to max 4 decimal points to yield like 81.52% when multiplied with 100%. In large projects, two decimal point reporting is useful and allows for incremental valuation without too much data loss after rounding down. Also I think, 2 decimal precision is commonly accepted standard.

Let me know If I missed something. Thanks

Edit: I have attached output for reports before my change (Coverlet.Console version 1.5.0) and after my change in zip.

Sample console output in version 1.5.0:

+-----------+-------+--------+--------+
| Module    | Line  | Branch | Method |
+-----------+-------+--------+--------+
| AppCenter | 13.8% | 25%    | 50%    |
+-----------+-------+--------+--------+

+---------+-------+--------+--------+
|         | Line  | Branch | Method |
+---------+-------+--------+--------+
| Total   | 13.8% | 25%    | 50%    |
+---------+-------+--------+--------+
| Average | 13.8% | 25%    | 50%    |
+---------+-------+--------+--------+

Sample console output after my change:

+-----------+--------+--------+--------+
| Module    | Line   | Branch | Method |
+-----------+--------+--------+--------+
| AppCenter | 13.79% | 25%    | 50%    |
+-----------+--------+--------+--------+

+---------+--------+--------+--------+
|         | Line   | Branch | Method |
+---------+--------+--------+--------+
| Total   | 13.79% | 25%    | 50%    |
+---------+--------+--------+--------+
| Average | 13.79% | 25%    | 50%    |
+---------+--------+--------+--------+

@codecov
Copy link

codecov bot commented May 4, 2019

Codecov Report

Merging #397 into master will increase coverage by 0.29%.
The diff coverage is 70.96%.

@@            Coverage Diff             @@
##           master     #397      +/-   ##
==========================================
+ Coverage   86.66%   86.96%   +0.29%     
==========================================
  Files          16       16              
  Lines        2130     2178      +48     
==========================================
+ Hits         1846     1894      +48     
  Misses        284      284

@MarcoRossignoli MarcoRossignoli requested a review from tonerdo May 4, 2019 20:41
get => Math.Round(Total == 0 ? 1 : Covered / Total, 4);
}

public double GetCoveragePercentage()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use property CoveragePercentace { get }

Copy link
Contributor Author

@sasivishnu sasivishnu May 5, 2019

Choose a reason for hiding this comment

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

Yeah, I can do that. Will convert method into prop CoveragePercentage { get }

return RoundDown(percentage);
}

private double RoundDown(double percentage)
Copy link
Collaborator

@MarcoRossignoli MarcoRossignoli May 4, 2019

Choose a reason for hiding this comment

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

Can you avoid RoundDown helper and use inline directly on CoveragePercentace prop, if I'm not mistaken this helper is private and used only in one method so it's not so useful extract it as helper.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, its used only in one place as of now.

I forget to ask this earlier, Average Coverage Percentage value could go more than 2 decimal precision since its calculated inline.
coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%");
Should I Floor the value with 2 decimal precision there also? Should I create MathHelper class under Helper folder, add this RoundDown method in the class & refer it in CoveragePercentage property and also during Average calculation? Is this fine?

Copy link
Contributor Author

@sasivishnu sasivishnu May 5, 2019

Choose a reason for hiding this comment

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

@MarcoRossignoli I have done other changes and ready for check-in. Also before & after report formats output.

I am waiting to see your reply on what to do with "Average Percentage" calculation and then check-in code fully at once either way.

Copy link
Collaborator

@MarcoRossignoli MarcoRossignoli May 5, 2019

Choose a reason for hiding this comment

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

I did deeper review...and I think that we should change a bit the idea.
We should avoid to change CoverageDetail object only to "round data", I don't like the idea to have members with same meaning but only different "formatting" seems a duplication to me, I mean GetCoveragePercentage is Percent formatted.
I like the idea of double MathHelper.RoundPercentage(double) in a file MathHelper.cs under Helpers folder and apply this helper in every place we need, in this way we can also apply it on Average Coverage Percentage.
For instance

var totalLinePercent =  MathHelper.RoundPercentage(summary.CalculateLineCoverage(result.Modules).Percent * 100);
...
var method = MathHelper.RoundPercentage(summary.CalculateMethodCoverage(module.Value));
...
 coverageTable.AddRow("Average", $"{MathHelper.RoundPercentage(totalLinePercent / numModules)}%",...

In this way we have also cetralized "percentage rounding" that we can apply in a uniform way in all codebase project.

Copy link
Collaborator

@MarcoRossignoli MarcoRossignoli May 5, 2019

Choose a reason for hiding this comment

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

could be cute to have an extension method

namespace Coverlet.Core.Helpers
{
   public static MathHelper 
   {
       public static double RoundPercentage(this double value)
       {
         ...
       }
   }
...

Copy link
Collaborator

Choose a reason for hiding this comment

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

The idea of helper was for future possible use of rounding percentage everywhere in same way, btw I'm ok also with this with "fix" where we need like above.

Copy link
Contributor Author

@sasivishnu sasivishnu May 6, 2019

Choose a reason for hiding this comment

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

I am planning to do both. Use Percent property only but add extension method in new MathHelper.cs class as public static double RoundPercentage(this double value).

So, it will be like Percent => { Total == 0? 1: ((Covered/Total)*100).RoundPercentage() }

Copy link
Collaborator

@MarcoRossignoli MarcoRossignoli May 6, 2019

Choose a reason for hiding this comment

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

@sasivishnu avoid helper at all, less code to review and maintain, if in future we'll need to reuse we'll move to helper, put all round alg in prop getter.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks @sasivishnu, let me know when you'd done this so I can merge. The rest of the code seems good to me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tonerdo Yep, I am done with my changes and pushed latest one.

@MarcoRossignoli
Copy link
Collaborator

MarcoRossignoli commented May 4, 2019

@sasivishnu can you please run before/after coverage with all format and show result to PR(like comment or attaching files) we need to be sure that reports are ok.

@MarcoRossignoli MarcoRossignoli requested a review from petli May 4, 2019 21:14
@sasivishnu
Copy link
Contributor Author

@sasivishnu can you please run before/after coverage with all format and show result to PR(like comment or attaching files) we need to be sure that reports are ok.

@MarcoRossignoli Yeah, I can do that. I will attach before and after reports for all five formats with console output too.

@@ -17,13 +17,13 @@ public void TestReport()
result.Identifier = Guid.NewGuid().ToString();

result.Modules = new Modules();
result.Modules.Add("Coverlet.Core.Reporters.Tests", CreateFirstDocuments());
result.Modules.Add("Coverlet.Core.Reporters.Tests", CreateFirstDocuments());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
result.Modules.Add("Coverlet.Core.Reporters.Tests", CreateFirstDocuments());
result.Modules.Add("Coverlet.Core.Reporters.Tests", CreateFirstDocuments());

@@ -8,7 +8,18 @@ public class CoverageDetails
public int Total { get; internal set; }
public double Percent
{
get => Math.Round(Total == 0 ? 1 : Covered / Total, 3);
get => Math.Round(Total == 0 ? 1 : Covered / Total, 4);
Copy link
Collaborator

Choose a reason for hiding this comment

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

All rounding down and decimal place code should go here

var totalLinePercent = summary.CalculateLineCoverage(result.Modules).Percent * 100;
var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent * 100;
var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent * 100;
var totalLinePercent = summary.CalculateLineCoverage(result.Modules).GetCoveragePercentage();
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can just be var totalLinePercent = summary.CalculateLineCoverage(result.Modules).Percent if you update the Percent property to contain the necessary calculations. Applies everywhere this new method is used

@sasivishnu
Copy link
Contributor Author

@sasivishnu can you please run before/after coverage with all format and show result to PR(like comment or attaching files) we need to be sure that reports are ok.

@MarcoRossignoli I have attached before and after sample report in first comment

{
get => Math.Round(Total == 0 ? 1 : Covered / Total, 3);
}
public double Percent => Total == 0 ? 1D : Math.Floor((Covered / Total) * 10000) / 100;
Copy link
Collaborator

Choose a reason for hiding this comment

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

should be 100D?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, good catch. Thanks. Will push the new commit with fix

@MarcoRossignoli
Copy link
Collaborator

MarcoRossignoli commented May 6, 2019

Files compared and looks ok to me there is only expected extra decimal for cobertura line-rate="0.1379"

Copy link
Collaborator

@MarcoRossignoli MarcoRossignoli left a comment

Choose a reason for hiding this comment

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

LGTM thank's a lot @sasivishnu!

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.

LGTM!

@tonerdo tonerdo merged commit 7cfe07e into coverlet-coverage:master May 7, 2019
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

3 participants