Skip to content

Commit 182766e

Browse files
daveMuellerMarcoRossignoli
authored andcommitted
Complete IFileSystem injection (#550)
Complete IFileSystem injection
1 parent 82a9208 commit 182766e

File tree

13 files changed

+140
-63
lines changed

13 files changed

+140
-63
lines changed

src/coverlet.collector/DataCollection/CoverageWrapper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger
3030
settings.MergeWith,
3131
settings.UseSourceLink,
3232
coverletLogger,
33-
(IInstrumentationHelper)DependencyInjection.Current.GetService(typeof(IInstrumentationHelper)));
33+
(IInstrumentationHelper)DependencyInjection.Current.GetService(typeof(IInstrumentationHelper)),
34+
(IFileSystem)DependencyInjection.Current.GetService(typeof(IFileSystem)));
3435
}
3536

3637
/// <summary>

src/coverlet.console/Program.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int Main(string[] args)
5959
// Adjust log level based on user input.
6060
logger.Level = verbosity.ParsedValue;
6161
}
62-
62+
var fileSystem = (IFileSystem)DependencyInjection.Current.GetService(typeof(IFileSystem));
6363
Coverage coverage = new Coverage(module.Value,
6464
includeFilters.Values.ToArray(),
6565
includeDirectories.Values.ToArray(),
@@ -71,7 +71,8 @@ static int Main(string[] args)
7171
mergeWith.Value(),
7272
useSourceLink.HasValue(),
7373
logger,
74-
(IInstrumentationHelper)DependencyInjection.Current.GetService(typeof(IInstrumentationHelper)));
74+
(IInstrumentationHelper)DependencyInjection.Current.GetService(typeof(IInstrumentationHelper)),
75+
fileSystem);
7576
coverage.PrepareModules();
7677

7778
Process process = new Process();
@@ -140,7 +141,7 @@ static int Main(string[] args)
140141

141142
var report = Path.Combine(directory, filename);
142143
logger.LogInformation($" Generating report '{report}'", important: true);
143-
File.WriteAllText(report, reporter.Report(result));
144+
fileSystem.WriteAllText(report, reporter.Report(result));
144145
}
145146
}
146147

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1-
namespace Coverlet.Core.Abstracts
1+
using System.IO;
2+
3+
namespace Coverlet.Core.Abstracts
24
{
3-
internal interface IFileSystem
5+
public interface IFileSystem
46
{
57
bool Exists(string path);
8+
9+
void WriteAllText(string path, string contents);
10+
11+
string ReadAllText(string path);
12+
13+
Stream OpenRead(string path);
14+
15+
void Copy(string sourceFileName, string destFileName, bool overwrite);
16+
17+
void Delete(string path);
18+
19+
Stream NewFileStream(string path, FileMode mode);
20+
21+
Stream NewFileStream(string path, FileMode mode, FileAccess access);
622
}
723
}

src/coverlet.core/Coverage.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.IO;
44
using System.Linq;
55
using Coverlet.Core.Abstracts;
6-
using Coverlet.Core.Helpers;
76
using Coverlet.Core.Instrumentation;
87
using Coverlet.Core.Logging;
98

@@ -27,6 +26,7 @@ public class Coverage
2726
private bool _useSourceLink;
2827
private ILogger _logger;
2928
private IInstrumentationHelper _instrumentationHelper;
29+
private IFileSystem _fileSystem;
3030
private List<InstrumenterResult> _results;
3131

3232
public string Identifier
@@ -45,7 +45,8 @@ public Coverage(string module,
4545
string mergeWith,
4646
bool useSourceLink,
4747
ILogger logger,
48-
IInstrumentationHelper instrumentationHelper)
48+
IInstrumentationHelper instrumentationHelper,
49+
IFileSystem fileSystem)
4950
{
5051
_module = module;
5152
_includeFilters = includeFilters;
@@ -59,12 +60,13 @@ public Coverage(string module,
5960
_useSourceLink = useSourceLink;
6061
_logger = logger;
6162
_instrumentationHelper = instrumentationHelper;
63+
_fileSystem = fileSystem;
6264

6365
_identifier = Guid.NewGuid().ToString();
6466
_results = new List<InstrumenterResult>();
6567
}
6668

67-
public Coverage(CoveragePrepareResult prepareResult, ILogger logger, IInstrumentationHelper instrumentationHelper)
69+
public Coverage(CoveragePrepareResult prepareResult, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem)
6870
{
6971
_identifier = prepareResult.Identifier;
7072
_module = prepareResult.Module;
@@ -73,6 +75,7 @@ public Coverage(CoveragePrepareResult prepareResult, ILogger logger, IInstrument
7375
_results = new List<InstrumenterResult>(prepareResult.Results);
7476
_logger = logger;
7577
_instrumentationHelper = instrumentationHelper;
78+
_fileSystem = fileSystem;
7679
}
7780

7881
public CoveragePrepareResult PrepareModules()
@@ -95,7 +98,7 @@ public CoveragePrepareResult PrepareModules()
9598
continue;
9699
}
97100

98-
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper);
101+
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem);
99102
if (instrumenter.CanInstrument())
100103
{
101104
_instrumentationHelper.BackupOriginalModule(module, _identifier);
@@ -216,9 +219,9 @@ public CoverageResult GetCoverageResult()
216219

217220
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results };
218221

219-
if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && File.Exists(_mergeWith))
222+
if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && _fileSystem.Exists(_mergeWith))
220223
{
221-
string json = File.ReadAllText(_mergeWith);
224+
string json = _fileSystem.ReadAllText(_mergeWith);
222225
coverageResult.Merge(JsonConvert.DeserializeObject<Modules>(json));
223226
}
224227

@@ -229,7 +232,7 @@ private void CalculateCoverage()
229232
{
230233
foreach (var result in _results)
231234
{
232-
if (!File.Exists(result.HitsFilePath))
235+
if (!_fileSystem.Exists(result.HitsFilePath))
233236
{
234237
// Hits file could be missed mainly for two reason
235238
// 1) Issue during module Unload()
@@ -250,7 +253,7 @@ private void CalculateCoverage()
250253
}
251254
}
252255

253-
using (var fs = new FileStream(result.HitsFilePath, FileMode.Open))
256+
using (var fs = _fileSystem.NewFileStream(result.HitsFilePath, FileMode.Open))
254257
using (var br = new BinaryReader(fs))
255258
{
256259
int hitCandidatesCount = br.ReadInt32();

src/coverlet.core/Helpers/FileSystem.cs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,47 @@
33

44
namespace Coverlet.Core.Helpers
55
{
6-
internal class FileSystem : IFileSystem
6+
public class FileSystem : IFileSystem
77
{
8-
public bool Exists(string path)
8+
// We need to partial mock this class on tests
9+
public virtual bool Exists(string path)
910
{
1011
return File.Exists(path);
1112
}
13+
14+
public void WriteAllText(string path, string contents)
15+
{
16+
File.WriteAllText(path, contents);
17+
}
18+
19+
public string ReadAllText(string path)
20+
{
21+
return File.ReadAllText(path);
22+
}
23+
24+
public Stream OpenRead(string path)
25+
{
26+
return File.OpenRead(path);
27+
}
28+
29+
public void Copy(string sourceFileName, string destFileName, bool overwrite)
30+
{
31+
File.Copy(sourceFileName, destFileName, overwrite);
32+
}
33+
34+
public void Delete(string path)
35+
{
36+
File.Delete(path);
37+
}
38+
39+
public Stream NewFileStream(string path, FileMode mode)
40+
{
41+
return new FileStream(path, mode);
42+
}
43+
44+
public Stream NewFileStream(string path, FileMode mode, FileAccess access)
45+
{
46+
return new FileStream(path, mode, access);
47+
}
1248
}
1349
}

src/coverlet.core/Helpers/InstrumentationHelper.cs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System.Reflection.PortableExecutable;
1010
using System.Text.RegularExpressions;
1111
using Coverlet.Core.Abstracts;
12-
using Coverlet.Core.Logging;
1312

1413
namespace Coverlet.Core.Helpers
1514
{
@@ -73,7 +72,7 @@ public string[] GetCoverableModules(string module, string[] directories, bool in
7372
public bool HasPdb(string module, out bool embedded)
7473
{
7574
embedded = false;
76-
using (var moduleStream = File.OpenRead(module))
75+
using (var moduleStream = _fileSystem.OpenRead(module))
7776
using (var peReader = new PEReader(moduleStream))
7877
{
7978
foreach (var entry in peReader.ReadDebugDirectory())
@@ -88,7 +87,7 @@ public bool HasPdb(string module, out bool embedded)
8887
return true;
8988
}
9089

91-
return File.Exists(codeViewData.Path);
90+
return _fileSystem.Exists(codeViewData.Path);
9291
}
9392
}
9493

@@ -99,7 +98,7 @@ public bool HasPdb(string module, out bool embedded)
9998
public bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
10099
{
101100
firstNotFoundDocument = "";
102-
using (FileStream moduleStream = File.OpenRead(module))
101+
using (Stream moduleStream = _fileSystem.OpenRead(module))
103102
using (var peReader = new PEReader(moduleStream))
104103
{
105104
foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
@@ -117,7 +116,7 @@ public bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNot
117116
// We verify all docs and return false if not all are present in local
118117
// We could have false negative if doc is not a source
119118
// Btw check for all possible extension could be weak approach
120-
if (!File.Exists(docName))
119+
if (!_fileSystem.Exists(docName))
121120
{
122121
firstNotFoundDocument = docName;
123122
return false;
@@ -136,15 +135,15 @@ public bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNot
136135
public bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
137136
{
138137
firstNotFoundDocument = "";
139-
using (var moduleStream = File.OpenRead(module))
138+
using (var moduleStream = _fileSystem.OpenRead(module))
140139
using (var peReader = new PEReader(moduleStream))
141140
{
142141
foreach (var entry in peReader.ReadDebugDirectory())
143142
{
144143
if (entry.Type == DebugDirectoryEntryType.CodeView)
145144
{
146145
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
147-
using FileStream pdbStream = new FileStream(codeViewData.Path, FileMode.Open);
146+
using Stream pdbStream = _fileSystem.NewFileStream(codeViewData.Path, FileMode.Open);
148147
using MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
149148
MetadataReader metadataReader = null;
150149
try
@@ -182,16 +181,16 @@ public void BackupOriginalModule(string module, string identifier)
182181
{
183182
var backupPath = GetBackupPath(module, identifier);
184183
var backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
185-
File.Copy(module, backupPath, true);
184+
_fileSystem.Copy(module, backupPath, true);
186185
if (!_backupList.TryAdd(module, backupPath))
187186
{
188187
throw new ArgumentException($"Key already added '{module}'");
189188
}
190189

191190
var symbolFile = Path.ChangeExtension(module, ".pdb");
192-
if (File.Exists(symbolFile))
191+
if (_fileSystem.Exists(symbolFile))
193192
{
194-
File.Copy(symbolFile, backupSymbolPath, true);
193+
_fileSystem.Copy(symbolFile, backupSymbolPath, true);
195194
if (!_backupList.TryAdd(symbolFile, backupSymbolPath))
196195
{
197196
throw new ArgumentException($"Key already added '{module}'");
@@ -210,18 +209,18 @@ public void RestoreOriginalModule(string module, string identifier)
210209

211210
_retryHelper.Retry(() =>
212211
{
213-
File.Copy(backupPath, module, true);
214-
File.Delete(backupPath);
212+
_fileSystem.Copy(backupPath, module, true);
213+
_fileSystem.Delete(backupPath);
215214
_backupList.TryRemove(module, out string _);
216215
}, retryStrategy, 10);
217216

218217
_retryHelper.Retry(() =>
219218
{
220-
if (File.Exists(backupSymbolPath))
219+
if (_fileSystem.Exists(backupSymbolPath))
221220
{
222221
string symbolFile = Path.ChangeExtension(module, ".pdb");
223-
File.Copy(backupSymbolPath, symbolFile, true);
224-
File.Delete(backupSymbolPath);
222+
_fileSystem.Copy(backupSymbolPath, symbolFile, true);
223+
_fileSystem.Delete(backupSymbolPath);
225224
_backupList.TryRemove(symbolFile, out string _);
226225
}
227226
}, retryStrategy, 10);
@@ -238,8 +237,8 @@ public void RestoreOriginalModules()
238237
string backupPath = _backupList[key];
239238
_retryHelper.Retry(() =>
240239
{
241-
File.Copy(backupPath, key, true);
242-
File.Delete(backupPath);
240+
_fileSystem.Copy(backupPath, key, true);
241+
_fileSystem.Delete(backupPath);
243242
_backupList.TryRemove(key, out string _);
244243
}, retryStrategy, 10);
245244
}
@@ -250,7 +249,7 @@ public void DeleteHitsFile(string path)
250249
// Retry hitting the hits file - retry up to 10 times, since the file could be locked
251250
// See: https://github.com/tonerdo/coverlet/issues/25
252251
var retryStrategy = CreateRetryStrategy();
253-
_retryHelper.Retry(() => File.Delete(path), retryStrategy, 10);
252+
_retryHelper.Retry(() => _fileSystem.Delete(path), retryStrategy, 10);
254253
}
255254

256255
public bool IsValidFilterExpression(string filter)

src/coverlet.core/Instrumentation/Instrumenter.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Linq;
77
using Coverlet.Core.Abstracts;
88
using Coverlet.Core.Attributes;
9-
using Coverlet.Core.Helpers;
109
using Coverlet.Core.Logging;
1110
using Coverlet.Core.Symbols;
1211
using Microsoft.Extensions.FileSystemGlobbing;
@@ -28,6 +27,7 @@ internal class Instrumenter
2827
private readonly bool _isCoreLibrary;
2928
private readonly ILogger _logger;
3029
private readonly IInstrumentationHelper _instrumentationHelper;
30+
private readonly IFileSystem _fileSystem;
3131
private InstrumenterResult _result;
3232
private FieldDefinition _customTrackerHitsArray;
3333
private FieldDefinition _customTrackerHitsFilePath;
@@ -48,7 +48,8 @@ public Instrumenter(
4848
string[] excludedAttributes,
4949
bool singleHit,
5050
ILogger logger,
51-
IInstrumentationHelper instrumentationHelper)
51+
IInstrumentationHelper instrumentationHelper,
52+
IFileSystem fileSystem)
5253
{
5354
_module = module;
5455
_identifier = identifier;
@@ -60,6 +61,7 @@ public Instrumenter(
6061
_isCoreLibrary = Path.GetFileNameWithoutExtension(_module) == "System.Private.CoreLib";
6162
_logger = logger;
6263
_instrumentationHelper = instrumentationHelper;
64+
_fileSystem = fileSystem;
6365
}
6466

6567
public bool CanInstrument()
@@ -136,7 +138,7 @@ public InstrumenterResult Instrument()
136138

137139
private void InstrumentModule()
138140
{
139-
using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite))
141+
using (var stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.ReadWrite))
140142
using (var resolver = new NetstandardAwareAssemblyResolver())
141143
{
142144
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));

0 commit comments

Comments
 (0)