66using ConsoleTables ;
77using Coverlet . Console . Logging ;
88using Coverlet . Core ;
9+ using Coverlet . Core . Enums ;
910using Coverlet . Core . Reporters ;
1011
1112using Microsoft . Extensions . CommandLineUtils ;
@@ -30,6 +31,7 @@ static int Main(string[] args)
3031 CommandOption formats = app . Option ( "-f|--format" , "Format of the generated coverage report." , CommandOptionType . MultipleValue ) ;
3132 CommandOption threshold = app . Option ( "--threshold" , "Exits with error if the coverage % is below value." , CommandOptionType . SingleValue ) ;
3233 CommandOption thresholdTypes = app . Option ( "--threshold-type" , "Coverage type to apply the threshold to." , CommandOptionType . MultipleValue ) ;
34+ CommandOption thresholdStat = app . Option ( "--threshold-stat" , "Coverage statistic used to enforce the threshold value." , CommandOptionType . SingleValue ) ;
3335 CommandOption excludeFilters = app . Option ( "--exclude" , "Filter expressions to exclude specific modules and types." , CommandOptionType . MultipleValue ) ;
3436 CommandOption includeFilters = app . Option ( "--include" , "Filter expressions to include only specific modules and types." , CommandOptionType . MultipleValue ) ;
3537 CommandOption excludedSourceFiles = app . Option ( "--exclude-by-file" , "Glob patterns specifying source files to exclude." , CommandOptionType . MultipleValue ) ;
@@ -59,8 +61,9 @@ static int Main(string[] args)
5961 process . WaitForExit ( ) ;
6062
6163 var dOutput = output . HasValue ( ) ? output . Value ( ) : Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar . ToString ( ) ;
62- var dThreshold = threshold . HasValue ( ) ? int . Parse ( threshold . Value ( ) ) : 0 ;
64+ var dThreshold = threshold . HasValue ( ) ? double . Parse ( threshold . Value ( ) ) : 0 ;
6365 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 ) ;
6467
6568 logger . LogInformation ( "\n Calculating coverage result..." ) ;
6669
@@ -79,7 +82,9 @@ static int Main(string[] args)
7982 {
8083 var reporter = new ReporterFactory ( format ) . CreateReporter ( ) ;
8184 if ( reporter == null )
85+ {
8286 throw new Exception ( $ "Specified output format '{ format } ' is not supported") ;
87+ }
8388
8489 if ( reporter . OutputType == ReporterOutputType . Console )
8590 {
@@ -100,13 +105,31 @@ static int Main(string[] args)
100105 }
101106 }
102107
103- var summary = new CoverageSummary ( ) ;
104- 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+
105126 var coverageTable = new ConsoleTable ( "Module" , "Line" , "Branch" , "Method" ) ;
106- var thresholdFailed = false ;
107- var overallLineCoverage = summary . CalculateLineCoverage ( result . Modules ) ;
108- var overallBranchCoverage = summary . CalculateBranchCoverage ( result . Modules ) ;
109- 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 ;
110133
111134 foreach ( var _module in result . Modules )
112135 {
@@ -115,37 +138,40 @@ static int Main(string[] args)
115138 var methodPercent = summary . CalculateMethodCoverage ( _module . Value ) . Percent * 100 ;
116139
117140 coverageTable . AddRow ( Path . GetFileNameWithoutExtension ( _module . Key ) , $ "{ linePercent } %", $ "{ branchPercent } %", $ "{ methodPercent } %") ;
141+ }
118142
119- 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 )
120159 {
121- if ( linePercent < dThreshold && dThresholdTypes . Contains ( "line" ) )
122- {
123- exceptionBuilder . AppendLine ( $ "'{ Path . GetFileNameWithoutExtension ( _module . Key ) } ' has a line coverage '{ linePercent } %' below specified threshold '{ dThreshold } %'") ;
124- thresholdFailed = true ;
125- }
126-
127- if ( branchPercent < dThreshold && dThresholdTypes . Contains ( "branch" ) )
128- {
129- exceptionBuilder . AppendLine ( $ "'{ Path . GetFileNameWithoutExtension ( _module . Key ) } ' has a branch coverage '{ branchPercent } %' below specified threshold '{ dThreshold } %'") ;
130- thresholdFailed = true ;
131- }
132-
133- if ( methodPercent < dThreshold && dThresholdTypes . Contains ( "method" ) )
134- {
135- exceptionBuilder . AppendLine ( $ "'{ Path . GetFileNameWithoutExtension ( _module . Key ) } ' has a method coverage '{ methodPercent } %' below specified threshold '{ dThreshold } %'") ;
136- thresholdFailed = true ;
137- }
160+ exceptionMessageBuilder . AppendLine ( $ "The { dThresholdStat . ToString ( ) . ToLower ( ) } line coverage is below the specified { dThreshold } ") ;
138161 }
139- }
140162
141- logger . LogInformation ( string . Empty ) ;
142- logger . LogInformation ( coverageTable . ToStringAlternative ( ) ) ;
143- logger . LogInformation ( $ "Total Line: { overallLineCoverage . Percent * 100 } %") ;
144- logger . LogInformation ( $ "Total Branch: { overallBranchCoverage . Percent * 100 } %") ;
145- 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+ }
146167
147- if ( thresholdFailed )
148- 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+ }
149175
150176 return process . ExitCode == 0 ? 0 : process . ExitCode ;
151177 } ) ;
0 commit comments