Skip to content

Commit a7a27e7

Browse files
committed
Apply PR from viktorhofer
1 parent e6a9524 commit a7a27e7

File tree

5 files changed

+87
-77
lines changed

5 files changed

+87
-77
lines changed

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,19 @@ Arguments:
5656
<ASSEMBLY> Path to the test assembly.
5757

5858
Options:
59-
-h|--help Show help information
60-
-v|--version Show version information
61-
-t|--target Path to the test runner application.
62-
-a|--targetargs Arguments to be passed to the test runner.
63-
-o|--output Output of the generated coverage report
64-
-f|--format Format of the generated coverage report.
65-
--threshold Exits with error if the coverage % is below value.
66-
--threshold-type Coverage type to apply the threshold to.
67-
--exclude Filter expressions to exclude specific modules and types.
68-
--include Filter expressions to include specific modules and types.
69-
--exclude-by-file Glob patterns specifying source files to exclude.
70-
--merge-with Path to existing coverage result to merge.
59+
-h|--help Show help information
60+
-v|--version Show version information
61+
-t|--target Path to the test runner application.
62+
-a|--targetargs Arguments to be passed to the test runner.
63+
-o|--output Output of the generated coverage report
64+
-f|--format Format of the generated coverage report.
65+
--threshold Exits with error if the coverage % is below value.
66+
--threshold-type Coverage type to apply the threshold to.
67+
--exclude Filter expressions to exclude specific modules and types.
68+
--include Filter expressions to include specific modules and types.
69+
--include-directories Include directories containing additional assemblies to be instrumented.
70+
--exclude-by-file Glob patterns specifying source files to exclude.
71+
--merge-with Path to existing coverage result to merge.
7172
```
7273
7374
#### Code Coverage

src/coverlet.core/Coverage.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public Coverage(string module, string[] excludeFilters, string[] includeFilters,
3232
_module = module;
3333
_excludeFilters = excludeFilters;
3434
_includeFilters = includeFilters;
35-
_includeDirectories = includeDirectories;
35+
_includeDirectories = includeDirectories ?? Array.Empty<string>();
3636
_excludedSourceFiles = excludedSourceFiles;
3737
_mergeWith = mergeWith;
3838

@@ -49,16 +49,26 @@ public void PrepareModules()
4949

5050
foreach (var module in modules)
5151
{
52-
if (InstrumentationHelper.IsModuleExcluded(module, _excludeFilters)
53-
|| !InstrumentationHelper.IsModuleIncluded(module, _includeFilters))
52+
if (InstrumentationHelper.IsModuleExcluded(module, _excludeFilters) ||
53+
!InstrumentationHelper.IsModuleIncluded(module, _includeFilters))
5454
continue;
5555

5656
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, excludes);
5757
if (instrumenter.CanInstrument())
5858
{
5959
InstrumentationHelper.BackupOriginalModule(module, _identifier);
60-
var result = instrumenter.Instrument();
61-
_results.Add(result);
60+
61+
// Guard code path and restore if instrumentation fails.
62+
try
63+
{
64+
var result = instrumenter.Instrument();
65+
_results.Add(result);
66+
}
67+
catch (Exception)
68+
{
69+
InstrumentationHelper.RestoreOriginalModule(module, _identifier);
70+
throw;
71+
}
6272
}
6373
}
6474
}
@@ -148,12 +158,11 @@ public CoverageResult GetCoverageResult()
148158
}
149159
}
150160

151-
modules.Add(result.ModulePath, documents);
161+
modules.Add(Path.GetFileName(result.ModulePath), documents);
152162
InstrumentationHelper.RestoreOriginalModule(result.ModulePath, _identifier);
153163
}
154164

155-
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = new Modules() };
156-
coverageResult.Merge(modules);
165+
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules };
157166

158167
if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && File.Exists(_mergeWith))
159168
{

src/coverlet.core/CoverageResult.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.IO;
34
using System.Linq;
@@ -44,53 +45,51 @@ internal void Merge(Modules modules)
4445
{
4546
foreach (var module in modules)
4647
{
47-
var existingKey = Modules.Keys.SingleOrDefault(key => Path.GetFileName(key) == Path.GetFileName(module.Key));
48-
49-
if (existingKey == null)
48+
if (!this.Modules.Keys.Contains(module.Key))
5049
{
5150
this.Modules.Add(module.Key, module.Value);
5251
}
5352
else
5453
{
5554
foreach (var document in module.Value)
5655
{
57-
if (!this.Modules[existingKey].ContainsKey(document.Key))
56+
if (!this.Modules[module.Key].ContainsKey(document.Key))
5857
{
59-
this.Modules[existingKey].Add(document.Key, document.Value);
58+
this.Modules[module.Key].Add(document.Key, document.Value);
6059
}
6160
else
6261
{
6362
foreach (var @class in document.Value)
6463
{
65-
if (!this.Modules[existingKey][document.Key].ContainsKey(@class.Key))
64+
if (!this.Modules[module.Key][document.Key].ContainsKey(@class.Key))
6665
{
67-
this.Modules[existingKey][document.Key].Add(@class.Key, @class.Value);
66+
this.Modules[module.Key][document.Key].Add(@class.Key, @class.Value);
6867
}
6968
else
7069
{
7170
foreach (var method in @class.Value)
7271
{
73-
if (!this.Modules[existingKey][document.Key][@class.Key].ContainsKey(method.Key))
72+
if (!this.Modules[module.Key][document.Key][@class.Key].ContainsKey(method.Key))
7473
{
75-
this.Modules[existingKey][document.Key][@class.Key].Add(method.Key, method.Value);
74+
this.Modules[module.Key][document.Key][@class.Key].Add(method.Key, method.Value);
7675
}
7776
else
7877
{
7978
foreach (var line in method.Value.Lines)
8079
{
81-
if (!this.Modules[existingKey][document.Key][@class.Key][method.Key].Lines.ContainsKey(line.Key))
80+
if (!this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines.ContainsKey(line.Key))
8281
{
83-
this.Modules[existingKey][document.Key][@class.Key][method.Key].Lines.Add(line.Key, line.Value);
82+
this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines.Add(line.Key, line.Value);
8483
}
8584
else
8685
{
87-
this.Modules[existingKey][document.Key][@class.Key][method.Key].Lines[line.Key] += line.Value;
86+
this.Modules[module.Key][document.Key][@class.Key][method.Key].Lines[line.Key] += line.Value;
8887
}
8988
}
9089

9190
foreach (var branch in method.Value.Branches)
9291
{
93-
var branches = this.Modules[existingKey][document.Key][@class.Key][method.Key].Branches;
92+
var branches = this.Modules[module.Key][document.Key][@class.Key][method.Key].Branches;
9493
var branchInfo = branches.FirstOrDefault(b => b.EndOffset == branch.EndOffset && b.Line == branch.Line && b.Offset == branch.Offset && b.Ordinal == branch.Ordinal && b.Path == branch.Path);
9594
if (branchInfo == null)
9695
branches.Add(branch);

src/coverlet.core/Helpers/InstrumentationHelper.cs

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
43
using System.Diagnostics;
5-
using System.Globalization;
64
using System.IO;
75
using System.Linq;
86
using System.Reflection;
97
using System.Reflection.PortableExecutable;
10-
using System.Security.Cryptography;
11-
using System.Text;
128
using System.Text.RegularExpressions;
139

1410
using Microsoft.Extensions.FileSystemGlobbing;
@@ -20,15 +16,45 @@ internal static class InstrumentationHelper
2016
{
2117
public static string[] GetCoverableModules(string module, string[] includeDirectories)
2218
{
23-
var moduleDirectory = Path.GetDirectoryName(module);
24-
var files = new List<string>(Directory.GetFiles(moduleDirectory));
19+
Debug.Assert(includeDirectories != null, "Parameter " + nameof(includeDirectories) + " in method " +
20+
nameof(InstrumentationHelper) + "." + nameof(GetCoverableModules) + " must not be null");
2521

26-
if (includeDirectories != null)
27-
foreach (var includeDirectory in ExpandIncludeDirectories(includeDirectories, moduleDirectory))
28-
files.AddRange(Directory.GetFiles(includeDirectory));
22+
string moduleDirectory = Path.GetDirectoryName(module);
23+
if (moduleDirectory == string.Empty)
24+
{
25+
moduleDirectory = Directory.GetCurrentDirectory();
26+
}
27+
28+
var dirs = new List<string>(1 + includeDirectories.Length)
29+
{
30+
// Add the test assembly's directory.
31+
moduleDirectory
32+
};
2933

30-
return files.Where(m => IsAssembly(m) && Path.GetFileName(m) != Path.GetFileName(module))
31-
.Distinct().ToArray();
34+
// Prepare all the directories in which we probe for modules.
35+
foreach (var includeDirectory in includeDirectories.Where(d => d != null))
36+
{
37+
var fullPath = (!Path.IsPathRooted(includeDirectory)
38+
? Path.GetFullPath(Path.Combine(moduleDirectory, includeDirectory))
39+
: includeDirectory).TrimEnd('*');
40+
41+
if (!Directory.Exists(fullPath)) continue;
42+
43+
if (includeDirectory.EndsWith("*", StringComparison.Ordinal))
44+
dirs.AddRange(Directory.GetDirectories(fullPath));
45+
else
46+
dirs.Add(fullPath);
47+
}
48+
49+
// The test module's name must be unique.
50+
var uniqueModules = new HashSet<string>
51+
{
52+
Path.GetFileName(module)
53+
};
54+
55+
return dirs.SelectMany(d => Directory.EnumerateFiles(d))
56+
.Where(m => IsAssembly(m) && uniqueModules.Add(Path.GetFileName(m)))
57+
.ToArray();
3258
}
3359

3460
public static bool HasPdb(string module)
@@ -254,32 +280,11 @@ private static bool IsTypeFilterMatch(string module, string type, string[] filte
254280
return false;
255281
}
256282

257-
private static IEnumerable<string> ExpandIncludeDirectories(string[] includeDirectories, string moduleDirectory)
258-
{
259-
var result = new List<string>(includeDirectories.Length);
260-
261-
foreach (var includeDirectory in includeDirectories.Where(d => d != null))
262-
{
263-
var fullPath = (!Path.IsPathRooted(includeDirectory)
264-
? Path.GetFullPath(Path.Combine(moduleDirectory, includeDirectory))
265-
: includeDirectory).TrimEnd('*');
266-
267-
if (!Directory.Exists(fullPath)) continue;
268-
269-
if (includeDirectory.EndsWith("*", StringComparison.Ordinal))
270-
result.AddRange(Directory.GetDirectories(fullPath));
271-
else
272-
result.Add(fullPath);
273-
}
274-
275-
return result;
276-
}
277-
278283
private static string GetBackupPath(string module, string identifier)
279284
{
280285
return Path.Combine(
281286
Path.GetTempPath(),
282-
Path.GetFileNameWithoutExtension(module) + "_" + GetPathHash(Path.GetDirectoryName(module)) + "_" + identifier + ".dll"
287+
Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
283288
);
284289
}
285290

@@ -304,11 +309,14 @@ private static string WildcardToRegex(string pattern)
304309

305310
private static bool IsAssembly(string filePath)
306311
{
312+
Debug.Assert(filePath != null, "Parameter " + nameof(filePath) + " in " + nameof(InstrumentationHelper) +
313+
"." + nameof(IsAssembly) + " must not be null.");
314+
315+
if (!(filePath.EndsWith(".exe") || filePath.EndsWith(".dll")))
316+
return false;
317+
307318
try
308319
{
309-
if (!(filePath.EndsWith(".exe") || filePath.EndsWith(".dll")))
310-
return false;
311-
312320
AssemblyName.GetAssemblyName(filePath);
313321
return true;
314322
}
@@ -317,13 +325,6 @@ private static bool IsAssembly(string filePath)
317325
return false;
318326
}
319327
}
320-
321-
private static string GetPathHash(string path)
322-
{
323-
using (var md5 = MD5.Create())
324-
return BitConverter.ToString(md5.ComputeHash(Encoding.Unicode.GetBytes(path)))
325-
.Replace("-", string.Empty);
326-
}
327328
}
328329
}
329330

test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class InstrumentationHelperTests
1212
public void TestGetDependencies()
1313
{
1414
string module = typeof(InstrumentationHelperTests).Assembly.Location;
15-
var modules = InstrumentationHelper.GetCoverableModules(module, null);
15+
var modules = InstrumentationHelper.GetCoverableModules(module, Array.Empty<string>());
1616
Assert.False(Array.Exists(modules, m => m == module));
1717
}
1818

0 commit comments

Comments
 (0)