44using System . Text ;
55using ConsoleTables ;
66using Coverlet . Core ;
7+ using Coverlet . Core . Enums ;
78using Coverlet . Core . Reporters ;
89using Microsoft . Build . Framework ;
910using 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 {
0 commit comments