Skip to content

Commit bdb6108

Browse files
committed
update msbuild task and global tool to use new threshold stat options
1 parent 4e029c3 commit bdb6108

File tree

3 files changed

+128
-69
lines changed

3 files changed

+128
-69
lines changed

src/coverlet.console/Program.cs

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using ConsoleTables;
77
using Coverlet.Console.Logging;
88
using Coverlet.Core;
9+
using Coverlet.Core.Enums;
910
using Coverlet.Core.Reporters;
1011

1112
using Microsoft.Extensions.CommandLineUtils;
@@ -60,8 +61,9 @@ static int Main(string[] args)
6061
process.WaitForExit();
6162

6263
var dOutput = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
63-
var dThreshold = threshold.HasValue() ? int.Parse(threshold.Value()) : 0;
64+
var dThreshold = threshold.HasValue() ? double.Parse(threshold.Value()) : 0;
6465
var dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List<string>(new string[] { "line", "branch", "method" });
66+
var dThresholdStat = thresholdStat.HasValue() ? Enum.Parse<ThresholdStatistic>(thresholdStat.Value(), true) : Enum.Parse<ThresholdStatistic>("minimum", true);
6567

6668
logger.LogInformation("\nCalculating coverage result...");
6769

@@ -80,7 +82,9 @@ static int Main(string[] args)
8082
{
8183
var reporter = new ReporterFactory(format).CreateReporter();
8284
if (reporter == null)
85+
{
8386
throw new Exception($"Specified output format '{format}' is not supported");
87+
}
8488

8589
if (reporter.OutputType == ReporterOutputType.Console)
8690
{
@@ -101,13 +105,31 @@ static int Main(string[] args)
101105
}
102106
}
103107

104-
var summary = new CoverageSummary();
105-
var exceptionBuilder = new StringBuilder();
108+
var thresholdTypeFlags = ThresholdTypeFlags.None;
109+
110+
foreach (var thresholdType in dThresholdTypes)
111+
{
112+
if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
113+
{
114+
thresholdTypeFlags |= ThresholdTypeFlags.Line;
115+
}
116+
else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
117+
{
118+
thresholdTypeFlags |= ThresholdTypeFlags.Branch;
119+
}
120+
else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
121+
{
122+
thresholdTypeFlags |= ThresholdTypeFlags.Method;
123+
}
124+
}
125+
106126
var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
107-
var thresholdFailed = false;
108-
var overallLineCoverage = summary.CalculateLineCoverage(result.Modules);
109-
var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
110-
var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);
127+
var summary = new CoverageSummary();
128+
int numModules = result.Modules.Count;
129+
130+
var totalLinePercent = summary.CalculateLineCoverage(result.Modules).Percent * 100;
131+
var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent * 100;
132+
var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent * 100;
111133

112134
foreach (var _module in result.Modules)
113135
{
@@ -116,37 +138,40 @@ static int Main(string[] args)
116138
var methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent * 100;
117139

118140
coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
141+
}
119142

120-
if (dThreshold > 0)
143+
logger.LogInformation(coverageTable.ToStringAlternative());
144+
145+
coverageTable.Columns.Clear();
146+
coverageTable.Rows.Clear();
147+
148+
coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
149+
coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
150+
coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%");
151+
152+
logger.LogInformation(coverageTable.ToStringAlternative());
153+
154+
thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, dThreshold, thresholdTypeFlags, dThresholdStat);
155+
if (thresholdTypeFlags != ThresholdTypeFlags.None)
156+
{
157+
var exceptionMessageBuilder = new StringBuilder();
158+
if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
121159
{
122-
if (linePercent < dThreshold && dThresholdTypes.Contains("line"))
123-
{
124-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a line coverage '{linePercent}%' below specified threshold '{dThreshold}%'");
125-
thresholdFailed = true;
126-
}
127-
128-
if (branchPercent < dThreshold && dThresholdTypes.Contains("branch"))
129-
{
130-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a branch coverage '{branchPercent}%' below specified threshold '{dThreshold}%'");
131-
thresholdFailed = true;
132-
}
133-
134-
if (methodPercent < dThreshold && dThresholdTypes.Contains("method"))
135-
{
136-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a method coverage '{methodPercent}%' below specified threshold '{dThreshold}%'");
137-
thresholdFailed = true;
138-
}
160+
exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} line coverage is below the specified {dThreshold}");
139161
}
140-
}
141162

142-
logger.LogInformation(string.Empty);
143-
logger.LogInformation(coverageTable.ToStringAlternative());
144-
logger.LogInformation($"Total Line: {overallLineCoverage.Percent * 100}%");
145-
logger.LogInformation($"Total Branch: {overallBranchCoverage.Percent * 100}%");
146-
logger.LogInformation($"Total Method: {overallMethodCoverage.Percent * 100}%");
163+
if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
164+
{
165+
exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} branch coverage is below the specified {dThreshold}");
166+
}
147167

148-
if (thresholdFailed)
149-
throw new Exception(exceptionBuilder.ToString().TrimEnd(Environment.NewLine.ToCharArray()));
168+
if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
169+
{
170+
exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} method coverage is below the specified {dThreshold}");
171+
}
172+
173+
throw new Exception(exceptionMessageBuilder.ToString());
174+
}
150175

151176
return process.ExitCode == 0 ? 0 : process.ExitCode;
152177
});

src/coverlet.msbuild.tasks/CoverageResultTask.cs

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using ConsoleTables;
66
using Coverlet.Core;
7+
using Coverlet.Core.Enums;
78
using Coverlet.Core.Reporters;
89
using Microsoft.Build.Framework;
910
using Microsoft.Build.Utilities;
@@ -14,7 +15,7 @@ public class CoverageResultTask : Task
1415
{
1516
private string _output;
1617
private string _format;
17-
private int _threshold;
18+
private double _threshold;
1819
private string _thresholdType;
1920
private string _thresholdStat;
2021

@@ -33,7 +34,7 @@ public string OutputFormat
3334
}
3435

3536
[Required]
36-
public int Threshold
37+
public double Threshold
3738
{
3839
get { return _threshold; }
3940
set { _threshold = value; }
@@ -77,7 +78,9 @@ public override bool Execute()
7778
{
7879
var reporter = new ReporterFactory(format).CreateReporter();
7980
if (reporter == null)
81+
{
8082
throw new Exception($"Specified output format '{format}' is not supported");
83+
}
8184

8285
if (reporter.OutputType == ReporterOutputType.Console)
8386
{
@@ -98,14 +101,41 @@ public override bool Execute()
98101
}
99102
}
100103

101-
var thresholdFailed = false;
102-
var thresholdTypes = _thresholdType.Split(',').Select(t => t.Trim());
103-
var summary = new CoverageSummary();
104-
var exceptionBuilder = new StringBuilder();
104+
var thresholdTypeFlags = ThresholdTypeFlags.None;
105+
var thresholdStat = ThresholdStatistic.Minimum;
106+
107+
foreach (var thresholdType in _thresholdType.Split(',').Select(t => t.Trim()))
108+
{
109+
if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
110+
{
111+
thresholdTypeFlags |= ThresholdTypeFlags.Line;
112+
}
113+
else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
114+
{
115+
thresholdTypeFlags |= ThresholdTypeFlags.Branch;
116+
}
117+
else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
118+
{
119+
thresholdTypeFlags |= ThresholdTypeFlags.Method;
120+
}
121+
}
122+
123+
if (_thresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
124+
{
125+
thresholdStat = ThresholdStatistic.Average;
126+
}
127+
else if (_thresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase))
128+
{
129+
thresholdStat = ThresholdStatistic.Total;
130+
}
131+
105132
var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
106-
var overallLineCoverage = summary.CalculateLineCoverage(result.Modules);
107-
var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
108-
var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);
133+
var summary = new CoverageSummary();
134+
int numModules = result.Modules.Count;
135+
136+
var totalLinePercent = summary.CalculateLineCoverage(result.Modules).Percent * 100;
137+
var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent * 100;
138+
var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent * 100;
109139

110140
foreach (var module in result.Modules)
111141
{
@@ -114,37 +144,41 @@ public override bool Execute()
114144
var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent * 100;
115145

116146
coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
117-
118-
if (_threshold > 0)
119-
{
120-
if (linePercent < _threshold && thresholdTypes.Contains("line", StringComparer.OrdinalIgnoreCase))
121-
{
122-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a line coverage '{linePercent}%' below specified threshold '{_threshold}%'");
123-
thresholdFailed = true;
124-
}
125-
126-
if (branchPercent < _threshold && thresholdTypes.Contains("branch", StringComparer.OrdinalIgnoreCase))
127-
{
128-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a branch coverage '{branchPercent}%' below specified threshold '{_threshold}%'");
129-
thresholdFailed = true;
130-
}
131-
132-
if (methodPercent < _threshold && thresholdTypes.Contains("method", StringComparer.OrdinalIgnoreCase))
133-
{
134-
exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a method coverage '{methodPercent}%' below specified threshold '{_threshold}%'");
135-
thresholdFailed = true;
136-
}
137-
}
138147
}
139148

140149
Console.WriteLine();
141150
Console.WriteLine(coverageTable.ToStringAlternative());
142-
Console.WriteLine($"Total Line: {overallLineCoverage.Percent * 100}%");
143-
Console.WriteLine($"Total Branch: {overallBranchCoverage.Percent * 100}%");
144-
Console.WriteLine($"Total Method: {overallMethodCoverage.Percent * 100}%");
145151

146-
if (thresholdFailed)
147-
throw new Exception(exceptionBuilder.ToString().TrimEnd(Environment.NewLine.ToCharArray()));
152+
coverageTable.Columns.Clear();
153+
coverageTable.Rows.Clear();
154+
155+
coverageTable.AddColumn(new [] { "", "Line", "Branch", "Method"});
156+
coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
157+
coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%");
158+
159+
Console.WriteLine(coverageTable.ToStringAlternative());
160+
161+
thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, _threshold, thresholdTypeFlags, thresholdStat);
162+
if (thresholdTypeFlags != ThresholdTypeFlags.None)
163+
{
164+
var exceptionMessageBuilder = new StringBuilder();
165+
if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
166+
{
167+
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {_threshold}");
168+
}
169+
170+
if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
171+
{
172+
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {_threshold}");
173+
}
174+
175+
if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
176+
{
177+
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {_threshold}");
178+
}
179+
180+
throw new Exception(exceptionMessageBuilder.ToString());
181+
}
148182
}
149183
catch (Exception ex)
150184
{

src/coverlet.msbuild/coverlet.msbuild.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
<CoverletOutput Condition="$(CoverletOutput) == ''">$([MSBuild]::EnsureTrailingSlash('$(MSBuildProjectDirectory)'))</CoverletOutput>
1313
<Threshold Condition="$(Threshold) == ''">0</Threshold>
1414
<ThresholdType Condition="$(ThresholdType) == ''">line,branch,method</ThresholdType>
15-
<ThresholdStat Condition="$(ThresholdStat) == ''">Minimum</ThresholdStat>
15+
<ThresholdStat Condition="$(ThresholdStat) == ''">minimum</ThresholdStat>
1616
</PropertyGroup>
1717
</Project>

0 commit comments

Comments
 (0)