diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index f41755f..420575d 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -55,10 +55,10 @@ namespace Coverlet.Core foreach (var result in _results) { Documents documents = new Documents(); - foreach (var doc in result.Documents) + foreach (var doc in result.Documents.Values) { // Construct Line Results - foreach (var line in doc.Lines) + foreach (var line in doc.Lines.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { @@ -91,7 +91,7 @@ namespace Coverlet.Core } // Construct Branch Results - foreach (var branch in doc.Branches) + foreach (var branch in doc.Branches.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { @@ -147,55 +147,52 @@ namespace Coverlet.Core { foreach (var result in _results) { - var i = 0; - while (true) + if (!File.Exists(result.HitsFilePath)) { - var file = $"{result.HitsFilePath}_compressed_{i}"; - if(!File.Exists(file)) break; - - using (var fs = new FileStream(file, FileMode.Open)) - using (var gz = new GZipStream(fs, CompressionMode.Decompress)) - using (var sr = new StreamReader(gz)) + // File not instrumented, or nothing in it called. Warn about this? + continue; + } + + using (var fs = new FileStream(result.HitsFilePath, FileMode.Open)) + using (var sr = new StreamReader(fs)) + { + string row; + while ((row = sr.ReadLine()) != null) { - string row; - while ((row = sr.ReadLine()) != null) + var info = row.Split(','); + // Ignore malformed lines + if (info.Length != 5) + continue; + + bool isBranch = info[0] == "B"; + + if (!result.Documents.TryGetValue(info[1], out var document)) { - var info = row.Split(','); - // Ignore malformed lines - if (info.Length != 4) - continue; + continue; + } - bool isBranch = info[0] == "B"; + int start = int.Parse(info[2]); + int hits = int.Parse(info[4]); - var document = result.Documents.FirstOrDefault(d => d.Path == info[1]); - if (document == null) - continue; - - int start = int.Parse(info[2]); - - if (isBranch) + if (isBranch) + { + int ordinal = int.Parse(info[3]); + var branch = document.Branches[(start, ordinal)]; + branch.Hits = hits; + } + else + { + int end = int.Parse(info[3]); + for (int j = start; j <= end; j++) { - uint ordinal = uint.Parse(info[3]); - var branch = document.Branches.First(b => b.Number == start && b.Ordinal == ordinal); - if (branch.Hits != int.MaxValue) - branch.Hits += branch.Hits + 1; - } - else - { - int end = int.Parse(info[3]); - for (int j = start; j <= end; j++) - { - var line = document.Lines.First(l => l.Number == j); - if (line.Hits != int.MaxValue) - line.Hits = line.Hits + 1; - } + var line = document.Lines[j]; + line.Hits = hits; } } } - - InstrumentationHelper.DeleteHitsFile(file); - i++; } + + InstrumentationHelper.DeleteHitsFile(result.HitsFilePath); } } } diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index e1f833d..3b63e76 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -169,17 +169,16 @@ namespace Coverlet.Core.Instrumentation private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint) { - var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url); - if (document == null) - { + if (!_result.Documents.TryGetValue(sequencePoint.Document.Url, out var document)) + { document = new Document { Path = sequencePoint.Document.Url }; - _result.Documents.Add(document); + _result.Documents.Add(document.Path, document); } for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++) { - if (!document.Lines.Exists(l => l.Number == i)) - document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); + if (!document.Lines.ContainsKey(i)) + document.Lines.Add(i, new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); } string marker = $"L,{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine}"; @@ -197,15 +196,15 @@ namespace Coverlet.Core.Instrumentation private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { - var document = _result.Documents.FirstOrDefault(d => d.Path == branchPoint.Document); - if (document == null) - { + if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) + { document = new Document { Path = branchPoint.Document }; - _result.Documents.Add(document); + _result.Documents.Add(document.Path, document); } - if (!document.Branches.Exists(l => l.Number == branchPoint.StartLine && l.Ordinal == branchPoint.Ordinal)) - document.Branches.Add( + var key = (branchPoint.StartLine, (int)branchPoint.Ordinal); + if (!document.Branches.ContainsKey(key)) + document.Branches.Add(key, new Branch { Number = branchPoint.StartLine, diff --git a/src/coverlet.core/Instrumentation/InstrumenterResult.cs b/src/coverlet.core/Instrumentation/InstrumenterResult.cs index a2b92cd..615e2e3 100644 --- a/src/coverlet.core/Instrumentation/InstrumenterResult.cs +++ b/src/coverlet.core/Instrumentation/InstrumenterResult.cs @@ -22,21 +22,26 @@ namespace Coverlet.Core.Instrumentation { public Document() { - Lines = new List(); - Branches = new List(); + Lines = new Dictionary(); + Branches = new Dictionary<(int Line, int Ordinal), Branch>(); } public string Path; - public List Lines { get; private set; } - public List Branches { get; private set; } + + public Dictionary Lines { get; private set; } + public Dictionary<(int Line, int Ordinal), Branch> Branches { get; private set; } } internal class InstrumenterResult { - public InstrumenterResult() => Documents = new List(); + public InstrumenterResult() + { + Documents = new Dictionary(); + } + public string Module; public string HitsFilePath; public string ModulePath; - public List Documents { get; private set; } + public Dictionary Documents { get; private set; } } } \ No newline at end of file diff --git a/src/coverlet.tracker/CoverageTracker.cs b/src/coverlet.tracker/CoverageTracker.cs index 50f7f11..ce59608 100644 --- a/src/coverlet.tracker/CoverageTracker.cs +++ b/src/coverlet.tracker/CoverageTracker.cs @@ -2,47 +2,39 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.IO.Compression; - -using Coverlet.Tracker.Extensions; namespace Coverlet.Tracker { public static class CoverageTracker { - private static Dictionary> _markers; - private static Dictionary _markerFileCount; + private static Dictionary> _events; [ExcludeFromCodeCoverage] static CoverageTracker() { - _markers = new Dictionary>(); - _markerFileCount = new Dictionary(); + _events = new Dictionary>(); AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); AppDomain.CurrentDomain.DomainUnload += new EventHandler(CurrentDomain_ProcessExit); } [ExcludeFromCodeCoverage] - public static void MarkExecuted(string path, string marker) + public static void MarkExecuted(string file, string evt) { - lock (_markers) + lock (_events) { - _markers.TryAdd(path, new List()); - _markers[path].Add(marker); - _markerFileCount.TryAdd(path, 0); - if (_markers[path].Count >= 100000) + if (!_events.TryGetValue(file, out var fileEvents)) { - using (var fs = new FileStream($"{path}_compressed_{_markerFileCount[path]}", FileMode.OpenOrCreate)) - using (var gz = new GZipStream(fs, CompressionMode.Compress)) - using (var sw = new StreamWriter(gz)) - { - foreach (var line in _markers[path]) - { - sw.WriteLine(line); - } - } - _markers[path].Clear(); - _markerFileCount[path] = _markerFileCount[path] + 1; + fileEvents = new Dictionary(); + _events.Add(file, fileEvents); + } + + if (!fileEvents.TryGetValue(evt, out var count)) + { + fileEvents.Add(evt, 1); + } + else if (count < int.MaxValue) + { + fileEvents[evt] = count + 1; } } } @@ -50,22 +42,21 @@ namespace Coverlet.Tracker [ExcludeFromCodeCoverage] public static void CurrentDomain_ProcessExit(object sender, EventArgs e) { - lock (_markers) + lock (_events) { - foreach (var kvp in _markers) + foreach (var files in _events) { - using (var fs = new FileStream($"{kvp.Key}_compressed_{_markerFileCount[kvp.Key]}", FileMode.OpenOrCreate)) - using (var gz = new GZipStream(fs, CompressionMode.Compress)) - using (var sw = new StreamWriter(gz)) + using (var fs = new FileStream(files.Key, FileMode.Create)) + using (var sw = new StreamWriter(fs)) { - foreach (var line in kvp.Value) + foreach (var evt in files.Value) { - sw.WriteLine(line); + sw.WriteLine($"{evt.Key},{evt.Value}"); } } } - _markers.Clear(); + _events.Clear(); } } } diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 8f3c11b..196d0e3 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -30,10 +30,10 @@ namespace Coverlet.Core.Instrumentation.Tests var instrumenterTest = CreateInstrumentor(); var result = instrumenterTest.Instrumenter.Instrument(); - var doc = result.Documents.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + var doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); Assert.NotNull(doc); - var found = doc.Lines.Any(l => l.Class == excludedType.FullName); + var found = doc.Lines.Values.Any(l => l.Class == excludedType.FullName); Assert.False(found, "Class decorated with with exclude attribute should be excluded"); instrumenterTest.Directory.Delete(true);