Skip to content

Commit e03c2e2

Browse files
authored
Merge pull request #164 from pjanotti/include.option
Add include option
2 parents b5c7587 + 045ee5f commit e03c2e2

File tree

9 files changed

+141
-44
lines changed

9 files changed

+141
-44
lines changed

src/coverlet.console/Program.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ static int Main(string[] args)
3131
CommandOption formats = app.Option("-f|--format", "Format of the generated coverage report.", CommandOptionType.MultipleValue);
3232
CommandOption threshold = app.Option("--threshold", "Exits with error if the coverage % is below value.", CommandOptionType.SingleValue);
3333
CommandOption thresholdTypes = app.Option("--threshold-type", "Coverage type to apply the threshold to.", CommandOptionType.MultipleValue);
34-
CommandOption filters = app.Option("--exclude", "Filter expressions to exclude specific modules and types.", CommandOptionType.MultipleValue);
35-
CommandOption excludes = app.Option("--exclude-by-file", "Glob patterns specifying source files to exclude.", CommandOptionType.MultipleValue);
34+
CommandOption excludeFilters = app.Option("--exclude", "Filter expressions to exclude specific modules and types.", CommandOptionType.MultipleValue);
35+
CommandOption includeFilters = app.Option("--include", "Filter expressions to include only specific modules and types.", CommandOptionType.MultipleValue);
36+
CommandOption excludedSourceFiles = app.Option("--exclude-by-file", "Glob patterns specifying source files to exclude.", CommandOptionType.MultipleValue);
3637

3738
app.OnExecute(() =>
3839
{
@@ -42,7 +43,7 @@ static int Main(string[] args)
4243
if (!target.HasValue())
4344
throw new CommandParsingException(app, "Target must be specified.");
4445

45-
Coverage coverage = new Coverage(module.Value, filters.Values.ToArray(), excludes.Values.ToArray());
46+
Coverage coverage = new Coverage(module.Value, excludeFilters.Values.ToArray(), includeFilters.Values.ToArray(), excludedSourceFiles.Values.ToArray());
4647
coverage.PrepareModules();
4748

4849
Process process = new Process();

src/coverlet.core/Coverage.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4-
using System.IO.Compression;
54
using System.Linq;
65

76
using Coverlet.Core.Helpers;
@@ -13,36 +12,40 @@ public class Coverage
1312
{
1413
private string _module;
1514
private string _identifier;
16-
private string[] _filters;
17-
private string[] _excludes;
15+
private string[] _excludeFilters;
16+
private string[] _includeFilters;
17+
private string[] _excludedSourceFiles;
1818
private List<InstrumenterResult> _results;
1919

2020
public string Identifier
2121
{
2222
get { return _identifier; }
2323
}
2424

25-
public Coverage(string module, string[] filters, string[] excludes)
25+
public Coverage(string module, string[] excludeFilters, string[] includeFilters, string[] excludedSourceFiles)
2626
{
2727
_module = module;
28-
_filters = filters;
29-
_excludes = excludes;
28+
_excludeFilters = excludeFilters;
29+
_includeFilters = includeFilters;
30+
_excludedSourceFiles = excludedSourceFiles;
3031
_identifier = Guid.NewGuid().ToString();
3132
_results = new List<InstrumenterResult>();
3233
}
3334

3435
public void PrepareModules()
3536
{
3637
string[] modules = InstrumentationHelper.GetCoverableModules(_module);
37-
string[] excludes = InstrumentationHelper.GetExcludedFiles(_excludes);
38-
_filters = _filters?.Where(f => InstrumentationHelper.IsValidFilterExpression(f)).ToArray();
38+
string[] excludes = InstrumentationHelper.GetExcludedFiles(_excludedSourceFiles);
39+
_excludeFilters = _excludeFilters?.Where(f => InstrumentationHelper.IsValidFilterExpression(f)).ToArray();
40+
_includeFilters = _includeFilters?.Where(f => InstrumentationHelper.IsValidFilterExpression(f)).ToArray();
3941

4042
foreach (var module in modules)
4143
{
42-
if (InstrumentationHelper.IsModuleExcluded(module, _filters))
44+
if (InstrumentationHelper.IsModuleExcluded(module, _excludeFilters)
45+
|| !InstrumentationHelper.IsModuleIncluded(module, _includeFilters))
4346
continue;
4447

45-
var instrumenter = new Instrumenter(module, _identifier, _filters, excludes);
48+
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, excludes);
4649
if (instrumenter.CanInstrument())
4750
{
4851
InstrumentationHelper.BackupOriginalModule(module, _identifier);

src/coverlet.core/Helpers/InstrumentationHelper.cs

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
@@ -111,23 +112,23 @@ public static bool IsValidFilterExpression(string filter)
111112
return true;
112113
}
113114

114-
public static bool IsModuleExcluded(string module, string[] filters)
115+
public static bool IsModuleExcluded(string module, string[] excludeFilters)
115116
{
116-
if (filters == null)
117+
if (excludeFilters == null || excludeFilters.Length == 0)
117118
return false;
118119

119120
module = Path.GetFileNameWithoutExtension(module);
120121
if (module == null)
121122
return false;
122123

123-
foreach (var filter in filters)
124+
foreach (var filter in excludeFilters)
124125
{
125-
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
126126
string typePattern = filter.Substring(filter.IndexOf(']') + 1);
127127

128128
if (typePattern != "*")
129129
continue;
130130

131+
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
131132
modulePattern = WildcardToRegex(modulePattern);
132133

133134
var regex = new Regex(modulePattern);
@@ -139,30 +140,57 @@ public static bool IsModuleExcluded(string module, string[] filters)
139140
return false;
140141
}
141142

142-
public static bool IsTypeExcluded(string module, string type, string[] filters)
143+
public static bool IsModuleIncluded(string module, string[] includeFilters)
143144
{
144-
if (filters == null)
145-
return false;
145+
if (includeFilters == null || includeFilters.Length == 0)
146+
return true;
146147

147148
module = Path.GetFileNameWithoutExtension(module);
148149
if (module == null)
149150
return false;
150151

151-
foreach (var filter in filters)
152+
foreach (var filter in includeFilters)
152153
{
153-
string typePattern = filter.Substring(filter.IndexOf(']') + 1);
154154
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
155155

156-
typePattern = WildcardToRegex(typePattern);
156+
if (modulePattern == "*")
157+
return true;
158+
157159
modulePattern = WildcardToRegex(modulePattern);
158160

159-
if (new Regex(typePattern).IsMatch(type) && new Regex(modulePattern).IsMatch(module))
161+
var regex = new Regex(modulePattern);
162+
163+
if (regex.IsMatch(module))
160164
return true;
161165
}
162166

163167
return false;
164168
}
165169

170+
public static bool IsTypeExcluded(string module, string type, string[] excludeFilters)
171+
{
172+
if (excludeFilters == null || excludeFilters.Length == 0)
173+
return false;
174+
175+
module = Path.GetFileNameWithoutExtension(module);
176+
if (module == null)
177+
return false;
178+
179+
return IsTypeFilterMatch(module, type, excludeFilters);
180+
}
181+
182+
public static bool IsTypeIncluded(string module, string type, string[] includeFilters)
183+
{
184+
if (includeFilters == null || includeFilters.Length == 0)
185+
return true;
186+
187+
module = Path.GetFileNameWithoutExtension(module);
188+
if (module == null)
189+
return true;
190+
191+
return IsTypeFilterMatch(module, type, includeFilters);
192+
}
193+
166194
public static bool IsLocalMethod(string method)
167195
=> new Regex(WildcardToRegex("<*>*__*|*")).IsMatch(method);
168196

@@ -206,6 +234,26 @@ public static string[] GetExcludedFiles(string[] excludes)
206234
return files.Distinct().ToArray();
207235
}
208236

237+
private static bool IsTypeFilterMatch(string module, string type, string[] filters)
238+
{
239+
Debug.Assert(module != null);
240+
Debug.Assert(filters != null);
241+
242+
foreach (var filter in filters)
243+
{
244+
string typePattern = filter.Substring(filter.IndexOf(']') + 1);
245+
string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
246+
247+
typePattern = WildcardToRegex(typePattern);
248+
modulePattern = WildcardToRegex(modulePattern);
249+
250+
if (new Regex(typePattern).IsMatch(type) && new Regex(modulePattern).IsMatch(module))
251+
return true;
252+
}
253+
254+
return false;
255+
}
256+
209257
private static string GetBackupPath(string module, string identifier)
210258
{
211259
return Path.Combine(

src/coverlet.core/Instrumentation/Instrumenter.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ internal class Instrumenter
1919
{
2020
private readonly string _module;
2121
private readonly string _identifier;
22-
private readonly string[] _filters;
22+
private readonly string[] _excludeFilters;
23+
private readonly string[] _includeFilters;
2324
private readonly string[] _excludedFiles;
2425
private readonly static Lazy<MethodInfo> _markExecutedMethodLoader = new Lazy<MethodInfo>(GetMarkExecutedMethod);
2526
private InstrumenterResult _result;
2627

27-
public Instrumenter(string module, string identifier, string[] filters, string[] excludedFiles)
28+
public Instrumenter(string module, string identifier, string[] excludeFilters, string[] includeFilters, string[] excludedFiles)
2829
{
2930
_module = module;
3031
_identifier = identifier;
31-
_filters = filters;
32+
_excludeFilters = excludeFilters;
33+
_includeFilters = includeFilters;
3234
_excludedFiles = excludedFiles ?? Array.Empty<string>();
3335
}
3436

@@ -69,7 +71,8 @@ private void InstrumentModule()
6971
{
7072
var actualType = type.DeclaringType ?? type;
7173
if (!actualType.CustomAttributes.Any(IsExcludeAttribute)
72-
&& !InstrumentationHelper.IsTypeExcluded(_module, actualType.FullName, _filters))
74+
&& !InstrumentationHelper.IsTypeExcluded(_module, actualType.FullName, _excludeFilters)
75+
&& InstrumentationHelper.IsTypeIncluded(_module, actualType.FullName, _includeFilters))
7376
InstrumentType(type);
7477
}
7578

@@ -92,10 +95,10 @@ private void InstrumentType(TypeDefinition type)
9295
}
9396

9497
var ctors = type.GetConstructors();
95-
foreach (var ctor in ctors)
96-
{
98+
foreach (var ctor in ctors)
99+
{
97100
if (!ctor.CustomAttributes.Any(IsExcludeAttribute))
98-
InstrumentMethod(ctor);
101+
InstrumentMethod(ctor);
99102
}
100103
}
101104

@@ -173,7 +176,7 @@ private void InstrumentIL(MethodDefinition method)
173176
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
174177
{
175178
if (!_result.Documents.TryGetValue(sequencePoint.Document.Url, out var document))
176-
{
179+
{
177180
document = new Document { Path = sequencePoint.Document.Url };
178181
_result.Documents.Add(document.Path, document);
179182
}
@@ -200,7 +203,7 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor
200203
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint)
201204
{
202205
if (!_result.Documents.TryGetValue(branchPoint.Document, out var document))
203-
{
206+
{
204207
document = new Document { Path = branchPoint.Document };
205208
_result.Documents.Add(document.Path, document);
206209
}

src/coverlet.msbuild.tasks/InstrumentationTask.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class InstrumentationTask : Task
1010
private static Coverage _coverage;
1111
private string _path;
1212
private string _exclude;
13+
private string _include;
1314
private string _excludeByFile;
1415

1516
internal static Coverage Coverage
@@ -30,6 +31,12 @@ public string Exclude
3031
set { _exclude = value; }
3132
}
3233

34+
public string Include
35+
{
36+
get { return _include; }
37+
set { _include = value; }
38+
}
39+
3340
public string ExcludeByFile
3441
{
3542
get { return _excludeByFile; }
@@ -40,10 +47,11 @@ public override bool Execute()
4047
{
4148
try
4249
{
43-
var excludes = _excludeByFile?.Split(',');
44-
var filters = _exclude?.Split(',');
50+
var excludedSourceFiles = _excludeByFile?.Split(',');
51+
var excludeFilters = _exclude?.Split(',');
52+
var includeFilters = _include?.Split(',');
4553

46-
_coverage = new Coverage(_path, filters, excludes);
54+
_coverage = new Coverage(_path, excludeFilters, includeFilters, excludedSourceFiles);
4755
_coverage.PrepareModules();
4856
}
4957
catch (Exception ex)

test/coverlet.core.performancetest/PerformanceTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace coverlet.core.performancetest
99
/// Test the performance of coverlet by running a unit test that calls a reasonably big and complex test class.
1010
/// Enable the test, compile, then run the test in the command line:
1111
/// <code>
12-
/// dotnet test -p:CollectCoverage=true -p:CoverletOutputFormat=opencover test/coverlet.core.performa ncetest/
12+
/// dotnet test -p:CollectCoverage=true -p:CoverletOutputFormat=opencover test/coverlet.core.performancetest/
1313
/// </code>
1414
/// </summary>
1515
public class PerformanceTest

test/coverlet.core.tests/CoverageTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void TestCoverage()
2727
// Since Coverage only instruments dependancies, we need a fake module here
2828
var testModule = Path.Combine(directory.FullName, "test.module.dll");
2929

30-
var coverage = new Coverage(testModule, Array.Empty<string>(), Array.Empty<string>());
30+
var coverage = new Coverage(testModule, Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>());
3131
coverage.PrepareModules();
3232

3333
var result = coverage.GetCoverageResult();

0 commit comments

Comments
 (0)