Skip to content

Commit 9435f73

Browse files
authored
Merge pull request #68 from sjp/extra-coverage
Additional coverage reporting for properties and nested types
2 parents 5ede288 + a94f010 commit 9435f73

File tree

4 files changed

+152
-102
lines changed

4 files changed

+152
-102
lines changed

src/coverlet.core/Attributes/ExcludeFromCoverage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
namespace Coverlet.Core.Attributes
44
{
5-
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)]
6-
public class ExcludeFromCoverageAttribute : Attribute { }
5+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor)]
6+
public sealed class ExcludeFromCoverageAttribute : Attribute { }
77
}

src/coverlet.core/Helpers/InstrumentationHelper.cs

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using System.Reflection;
56
using System.Reflection.PortableExecutable;
6-
using Microsoft.Extensions.FileSystemGlobbing;
77

8-
using Coverlet.Core.Instrumentation;
8+
using Microsoft.Extensions.FileSystemGlobbing;
99
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
1010

1111
namespace Coverlet.Core.Helpers
@@ -15,7 +15,7 @@ internal static class InstrumentationHelper
1515
public static string[] GetDependencies(string module)
1616
{
1717
IEnumerable<string> modules = Directory.GetFiles(Path.GetDirectoryName(module), "*.dll");
18-
modules = modules.Where(a => Path.GetFileName(a) != Path.GetFileName(module));
18+
modules = modules.Where(a => IsAssembly(a) && Path.GetFileName(a) != Path.GetFileName(module));
1919
return modules.ToArray();
2020
}
2121

@@ -41,39 +41,29 @@ public static bool HasPdb(string module)
4141
public static void CopyCoverletDependency(string module)
4242
{
4343
var directory = Path.GetDirectoryName(module);
44-
if (Path.GetFileNameWithoutExtension(module) == "coverlet.core")
45-
return;
44+
var moduleFileName = Path.GetFileName(module);
4645

4746
var assembly = typeof(Coverage).Assembly;
4847
string name = Path.GetFileName(assembly.Location);
48+
if (name == moduleFileName)
49+
return;
50+
4951
File.Copy(assembly.Location, Path.Combine(directory, name), true);
5052
}
5153

5254
public static void BackupOriginalModule(string module, string identifier)
5355
{
54-
var backupPath = Path.Combine(
55-
Path.GetTempPath(),
56-
Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
57-
);
58-
56+
var backupPath = GetBackupPath(module, identifier);
5957
File.Copy(module, backupPath);
6058
}
6159

6260
public static void RestoreOriginalModule(string module, string identifier)
6361
{
64-
var backupPath = Path.Combine(
65-
Path.GetTempPath(),
66-
Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
67-
);
62+
var backupPath = GetBackupPath(module, identifier);
6863

6964
// Restore the original module - retry up to 10 times, since the destination file could be locked
7065
// See: https://github.com/tonerdo/coverlet/issues/25
71-
var currentSleep = 6;
72-
Func<TimeSpan> retryStrategy = () => {
73-
var sleep = TimeSpan.FromMilliseconds(currentSleep);
74-
currentSleep *= 2;
75-
return sleep;
76-
};
66+
var retryStrategy = CreateRetryStrategy();
7767

7868
RetryHelper.Retry(() => {
7969
File.Copy(backupPath, module, true);
@@ -85,13 +75,7 @@ public static IEnumerable<string> ReadHitsFile(string path)
8575
{
8676
// Retry hitting the hits file - retry up to 10 times, since the file could be locked
8777
// See: https://github.com/tonerdo/coverlet/issues/25
88-
var currentSleep = 6;
89-
Func<TimeSpan> retryStrategy = () =>
90-
{
91-
var sleep = TimeSpan.FromMilliseconds(currentSleep);
92-
currentSleep *= 2;
93-
return sleep;
94-
};
78+
var retryStrategy = CreateRetryStrategy();
9579

9680
return RetryHelper.Do(() => File.ReadLines(path), retryStrategy, 10);
9781
}
@@ -100,39 +84,33 @@ public static void DeleteHitsFile(string path)
10084
{
10185
// Retry hitting the hits file - retry up to 10 times, since the file could be locked
10286
// See: https://github.com/tonerdo/coverlet/issues/25
103-
var currentSleep = 6;
104-
Func<TimeSpan> retryStrategy = () => {
105-
var sleep = TimeSpan.FromMilliseconds(currentSleep);
106-
currentSleep *= 2;
107-
return sleep;
108-
};
87+
var retryStrategy = CreateRetryStrategy();
10988

11089
RetryHelper.Retry(() => File.Delete(path), retryStrategy, 10);
11190
}
112-
113-
public static IEnumerable<string> GetExcludedFiles(IEnumerable<string> excludeRules,
114-
string parentDir = null)
91+
92+
public static IEnumerable<string> GetExcludedFiles(IEnumerable<string> excludeRules,
93+
string parentDir = null)
11594
{
11695
const string RELATIVE_KEY = nameof(RELATIVE_KEY);
11796
parentDir = string.IsNullOrWhiteSpace(parentDir)? Directory.GetCurrentDirectory() : parentDir;
118-
97+
11998
if (excludeRules == null || !excludeRules.Any()) return Enumerable.Empty<string>();
120-
99+
121100
var matcherDict = new Dictionary<string, Matcher>(){ {RELATIVE_KEY, new Matcher()}};
122101
foreach (var excludeRule in excludeRules)
123102
{
124103
if (Path.IsPathRooted(excludeRule)) {
125104
var root = Path.GetPathRoot(excludeRule);
126105
if (!matcherDict.ContainsKey(root)) {
127106
matcherDict.Add(root, new Matcher());
128-
}
107+
}
129108
matcherDict[root].AddInclude(excludeRule.Substring(root.Length));
130109
} else {
131110
matcherDict[RELATIVE_KEY].AddInclude(excludeRule);
132111
}
133-
134112
}
135-
113+
136114
var files = new List<string>();
137115
foreach(var entry in matcherDict)
138116
{
@@ -144,9 +122,42 @@ public static IEnumerable<string> GetExcludedFiles(IEnumerable<string> excludeRu
144122
.Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path)));
145123
files.AddRange(currentFiles);
146124
}
147-
125+
148126
return files.Distinct();
149127
}
128+
129+
private static bool IsAssembly(string filePath)
130+
{
131+
try
132+
{
133+
AssemblyName.GetAssemblyName(filePath);
134+
return true;
135+
}
136+
catch
137+
{
138+
return false;
139+
}
140+
}
141+
142+
private static string GetBackupPath(string module, string identifier)
143+
{
144+
return Path.Combine(
145+
Path.GetTempPath(),
146+
Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
147+
);
148+
}
149+
150+
private static Func<TimeSpan> CreateRetryStrategy(int initialSleepSeconds = 6)
151+
{
152+
TimeSpan retryStrategy()
153+
{
154+
var sleep = TimeSpan.FromMilliseconds(initialSleepSeconds);
155+
initialSleepSeconds *= 2;
156+
return sleep;
157+
}
158+
159+
return retryStrategy;
160+
}
150161
}
151162
}
152163

src/coverlet.core/Helpers/RetryHelper.cs

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,60 @@
22
using System.Collections.Generic;
33
using System.Threading;
44

5-
// A slightly amended version of the code found here: https://stackoverflow.com/a/1563234/186184
6-
// This code allows for varying backoff strategies through the use of Func<TimeSpan>.
7-
public static class RetryHelper
5+
namespace Coverlet.Core
86
{
9-
/// <summary>
10-
/// Retry a void method.
11-
/// </summary>
12-
/// <param name="action">The action to perform</param>
13-
/// <param name="backoffStrategy">A function returning a Timespan defining the backoff strategy to use.</param>
14-
/// <param name="maxAttemptCount">The maximum number of retries before bailing out. Defaults to 3.</param>
15-
public static void Retry(
16-
Action action,
17-
Func<TimeSpan> backoffStrategy,
18-
int maxAttemptCount = 3)
7+
// A slightly amended version of the code found here: https://stackoverflow.com/a/1563234/186184
8+
// This code allows for varying backoff strategies through the use of Func<TimeSpan>.
9+
public static class RetryHelper
1910
{
20-
Do<object>(() =>
11+
/// <summary>
12+
/// Retry a void method.
13+
/// </summary>
14+
/// <param name="action">The action to perform</param>
15+
/// <param name="backoffStrategy">A function returning a Timespan defining the backoff strategy to use.</param>
16+
/// <param name="maxAttemptCount">The maximum number of retries before bailing out. Defaults to 3.</param>
17+
public static void Retry(
18+
Action action,
19+
Func<TimeSpan> backoffStrategy,
20+
int maxAttemptCount = 3)
2121
{
22-
action();
23-
return null;
24-
}, backoffStrategy, maxAttemptCount);
25-
}
26-
27-
/// <summary>
28-
/// Retry a method returning type T.
29-
/// </summary>
30-
/// <param name="action">The action to perform</param>
31-
/// <param name="backoffStrategy">A function returning a Timespan defining the backoff strategy to use.</param>
32-
/// <param name="maxAttemptCount">The maximum number of retries before bailing out. Defaults to 3.</param>
33-
public static T Do<T>(
34-
Func<T> action,
35-
Func<TimeSpan> backoffStrategy,
36-
int maxAttemptCount = 3)
37-
{
38-
var exceptions = new List<Exception>();
22+
Do<object>(() =>
23+
{
24+
action();
25+
return null;
26+
}, backoffStrategy, maxAttemptCount);
27+
}
3928

40-
for (int attempted = 0; attempted < maxAttemptCount; attempted++)
29+
/// <summary>
30+
/// Retry a method returning type T.
31+
/// </summary>
32+
/// <typeparam name="T">The type of the object to return</typeparam>
33+
/// <param name="action">The action to perform</param>
34+
/// <param name="backoffStrategy">A function returning a Timespan defining the backoff strategy to use.</param>
35+
/// <param name="maxAttemptCount">The maximum number of retries before bailing out. Defaults to 3.</param>
36+
public static T Do<T>(
37+
Func<T> action,
38+
Func<TimeSpan> backoffStrategy,
39+
int maxAttemptCount = 3)
4140
{
42-
try
41+
var exceptions = new List<Exception>();
42+
43+
for (int attempted = 0; attempted < maxAttemptCount; attempted++)
4344
{
44-
if (attempted > 0)
45+
try
4546
{
46-
Thread.Sleep(backoffStrategy());
47+
if (attempted > 0)
48+
{
49+
Thread.Sleep(backoffStrategy());
50+
}
51+
return action();
52+
}
53+
catch (Exception ex)
54+
{
55+
exceptions.Add(ex);
4756
}
48-
return action();
49-
}
50-
catch (Exception ex)
51-
{
52-
exceptions.Add(ex);
5357
}
58+
throw new AggregateException(exceptions);
5459
}
55-
throw new AggregateException(exceptions);
5660
}
5761
}

0 commit comments

Comments
 (0)