Skip to content

Commit 7708ee8

Browse files
author
Kester Maddock
committed
Encapsulated the map of file name to coverage lines with FileLineCoverage.
1 parent 9bf7101 commit 7708ee8

15 files changed

+105
-75
lines changed

FineCodeCoverageTests/FCCEngine_Tests.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using FineCodeCoverage.Options;
1616
using Moq;
1717
using NUnit.Framework;
18+
using SharedProject.Core.Model;
1819

1920
namespace Test
2021
{
@@ -333,7 +334,7 @@ private void VerifyLogsReloadCoverageStatus(ReloadCoverageStatus reloadCoverageS
333334
mocker.Verify<ILogger>(l => l.Log(fccEngine.GetLogReloadCoverageStatusMessage(reloadCoverageStatus)));
334335
}
335336

336-
private async Task<(string reportGeneratedHtmlContent, Dictionary<string, List<CoverageLine>> updatedCoverageLines)> RunToCompletion(bool noCoverageProjects)
337+
private async Task<(string reportGeneratedHtmlContent, FileLineCoverage updatedCoverageLines)> RunToCompletion(bool noCoverageProjects)
337338
{
338339
var coverageProject = CreateSuitableProject().Object;
339340
var mockReportGenerator = mocker.GetMock<IReportGeneratorUtil>();
@@ -352,10 +353,8 @@ private void VerifyLogsReloadCoverageStatus(ReloadCoverageStatus reloadCoverageS
352353

353354
var reportGeneratedHtmlContent = "<somehtml/>";
354355
mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified", It.IsAny<string>())).Returns(reportGeneratedHtmlContent);
355-
Dictionary<string, List<CoverageLine>> coverageLines = new Dictionary<string, List<CoverageLine>>()
356-
{
357-
{ "test", new List<CoverageLine>() { new CoverageLine() } }
358-
};
356+
var coverageLines = new FileLineCoverage();
357+
coverageLines.Add("test", new[] { new Line() });
359358
mocker.GetMock<ICoberturaUtil>().Setup(coberturaUtil => coberturaUtil.ProcessCoberturaXml(It.IsAny<string>())).Returns(coverageLines);
360359
if (noCoverageProjects)
361360
{
@@ -387,10 +386,8 @@ private async Task ThrowReadingReportHtml()
387386
}
388387
);
389388

390-
Dictionary<string, List<CoverageLine>> coverageLines = new Dictionary<string, List<CoverageLine>>()
391-
{
392-
{ "test", new List<CoverageLine>() { new CoverageLine() } }
393-
};
389+
var coverageLines = new FileLineCoverage();
390+
coverageLines.Add("test", new[] { new Line() });
394391
mocker.GetMock<ICoberturaUtil>().Setup(coberturaUtil => coberturaUtil.ProcessCoberturaXml(It.IsAny<string>())).Returns(coverageLines);
395392

396393
await ReloadInitializedCoverage(passedProject.Object);

SharedProject/Core/Cobertura/CoberturaUtil.cs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.IO;
88
using System.Windows.Documents;
99
using System;
10+
using SharedProject.Core.Model;
1011

1112
namespace FineCodeCoverage.Engine.Cobertura
1213
{
@@ -69,31 +70,18 @@ private CoverageReport LoadReport(string xmlFile)
6970
// return jsonText;
7071
//}
7172

72-
public Dictionary<string, List<CoverageLine>> ProcessCoberturaXml(string xmlFile)
73+
public FileLineCoverage ProcessCoberturaXml(string xmlFile)
7374
{
74-
var coverageLines = new Dictionary<string, List<CoverageLine>>(StringComparer.OrdinalIgnoreCase);
75+
var coverageLines = new FileLineCoverage();
7576

7677
coverageReport = LoadReport(xmlFile);
7778

7879
foreach (var package in coverageReport.Packages.Package)
7980
{
8081
foreach (var classs in package.Classes.Class)
8182
{
82-
if (!coverageLines.TryGetValue(classs.Filename, out var classCoverageLines))
83-
{
84-
classCoverageLines = new List<CoverageLine>();
85-
coverageLines.Add(string.Intern(classs.Filename), classCoverageLines);
86-
}
87-
88-
foreach (var line in classs.Lines.Line)
89-
{
90-
classCoverageLines.Add(new CoverageLine
91-
{
92-
Package = package,
93-
Class = classs,
94-
Line = line
95-
});
96-
}
83+
coverageLines.Add(classs.Filename, classs.Lines.Line);
84+
9785
}
9886
}
9987

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using System.Collections.Generic;
22
using FineCodeCoverage.Engine.Model;
3+
using SharedProject.Core.Model;
34

45
namespace FineCodeCoverage.Engine.Cobertura
56
{
67
interface ICoberturaUtil
78
{
8-
Dictionary<string, List<CoverageLine>> ProcessCoberturaXml(string xmlFile);
9+
FileLineCoverage ProcessCoberturaXml(string xmlFile);
910
string[] GetSourceFiles(string assemblyName, string qualifiedClassName, int file);
1011
}
1112
}

SharedProject/Core/FCCEngine.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@
1212
using FineCodeCoverage.Impl;
1313
using FineCodeCoverage.Options;
1414
using FineCodeCoverage.Output;
15+
using SharedProject.Core.Model;
1516

1617
namespace FineCodeCoverage.Engine
1718
{
1819
internal enum ReloadCoverageStatus { Start, Done, Cancelled, Error, Initializing };
1920

2021
internal class NewCoverageLinesMessage
2122
{
22-
public Dictionary<string, List<CoverageLine>> CoverageLines { get; set; }
23+
public SharedProject.Core.Model.FileLineCoverage CoverageLines { get; set; }
2324
}
2425

2526
internal class DisplayCoverageResultState
@@ -202,12 +203,12 @@ private void ClearCoverageLines()
202203
RaiseCoverageLines(null);
203204
}
204205

205-
private void RaiseCoverageLines(Dictionary<string, List<CoverageLine>> coverageLines)
206+
private void RaiseCoverageLines(FileLineCoverage coverageLines)
206207
{
207208
eventAggregator.SendMessage(new NewCoverageLinesMessage { CoverageLines = coverageLines});
208209
}
209210

210-
private void UpdateUI(Dictionary<string, List<CoverageLine>> coverageLines, string reportHtml)
211+
private void UpdateUI(FileLineCoverage coverageLines, string reportHtml)
211212
{
212213
RaiseCoverageLines(coverageLines);
213214
if (reportHtml == null)
@@ -217,7 +218,7 @@ private void UpdateUI(Dictionary<string, List<CoverageLine>> coverageLines, stri
217218
RaiseUpdateOutputWindow(reportHtml);
218219
}
219220

220-
private async System.Threading.Tasks.Task<(Dictionary<string, List<CoverageLine>> coverageLines,string reportFilePath)> RunAndProcessReportAsync(string[] coverOutputFiles, CancellationToken vsShutdownLinkedCancellationToken)
221+
private async System.Threading.Tasks.Task<(FileLineCoverage coverageLines,string reportFilePath)> RunAndProcessReportAsync(string[] coverOutputFiles, CancellationToken vsShutdownLinkedCancellationToken)
221222
{
222223
var reportOutputFolder = coverageOutputManager.GetReportOutputFolder();
223224
vsShutdownLinkedCancellationToken.ThrowIfCancellationRequested();
@@ -262,7 +263,7 @@ private async System.Threading.Tasks.Task PrepareCoverageProjectsAsync(List<ICov
262263
}
263264
}
264265

265-
private void DisplayCoverageResult(System.Threading.Tasks.Task<(Dictionary<string, List<CoverageLine>> coverageLines, string reportHtml)> t, object state)
266+
private void DisplayCoverageResult(System.Threading.Tasks.Task<(FileLineCoverage coverageLines, string reportHtml)> t, object state)
266267
{
267268
var displayCoverageResultState = (DisplayCoverageResultState)state;
268269
if (!IsVsShutdown)
@@ -321,7 +322,7 @@ public void RunAndProcessReport(string[] coberturaFiles, Action cleanUp = null)
321322
{
322323
RunCancellableCoverageTask(async (vsShutdownLinkedCancellationToken) =>
323324
{
324-
Dictionary<string, List<CoverageLine>> coverageLines = null;
325+
FileLineCoverage coverageLines = null;
325326
string reportHtml = null;
326327

327328
if (coberturaFiles.Any())
@@ -333,7 +334,7 @@ public void RunAndProcessReport(string[] coberturaFiles, Action cleanUp = null)
333334
}
334335

335336
private void RunCancellableCoverageTask(
336-
Func<CancellationToken,System.Threading.Tasks.Task<(Dictionary<string, List<CoverageLine>>, string)>> taskCreator, Action cleanUp)
337+
Func<CancellationToken,System.Threading.Tasks.Task<(FileLineCoverage, string)>> taskCreator, Action cleanUp)
337338
{
338339
var vsLinkedCancellationTokenSource = Reset();
339340
var vsShutdownLinkedCancellationToken = vsLinkedCancellationTokenSource.Token;
@@ -355,7 +356,7 @@ public void ReloadCoverage(Func<System.Threading.Tasks.Task<List<ICoverageProjec
355356
{
356357
RunCancellableCoverageTask(async (vsShutdownLinkedCancellationToken) =>
357358
{
358-
Dictionary<string, List<CoverageLine>> coverageLines = null;
359+
FileLineCoverage coverageLines = null;
359360
string reportHtml = null;
360361

361362
await PollInitializedStatusAsync(vsShutdownLinkedCancellationToken);

SharedProject/Core/Model/CoverageLine.cs

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using FineCodeCoverage.Engine.Cobertura;
2+
using FineCodeCoverage.Engine.Model;
3+
using Newtonsoft.Json.Linq;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Windows.Documents;
9+
using System.Windows.Media;
10+
11+
namespace SharedProject.Core.Model
12+
{
13+
// FileLineCoverage maps from a filename to the list of lines in the file
14+
internal class FileLineCoverage
15+
{
16+
private Dictionary<string, List<Line>> m_coverageLines = new Dictionary<string, List<Line>>(StringComparer.OrdinalIgnoreCase);
17+
18+
19+
public void Add(string filename, IEnumerable<Line> lines)
20+
{
21+
if (!m_coverageLines.TryGetValue(filename, out var classCoverageLines))
22+
{
23+
classCoverageLines = new List<Line>();
24+
m_coverageLines.Add(filename, classCoverageLines);
25+
}
26+
27+
classCoverageLines.AddRange(lines);
28+
classCoverageLines.Sort((a, b) => a.Number - b.Number);
29+
}
30+
31+
public IEnumerable<Line> GetLines(string filePath, int startLineNumber, int endLineNumber)
32+
{
33+
if (!m_coverageLines.TryGetValue(filePath, out var lines))
34+
yield break;
35+
36+
// binary search to find the first line
37+
int first = 0;
38+
int count = lines.Count;
39+
while (count > 0)
40+
{
41+
int step = count / 2;
42+
int it = first + step;
43+
if (lines[it].Number < startLineNumber)
44+
{
45+
first = ++it;
46+
count -= step + 1;
47+
}
48+
else
49+
{
50+
count = step;
51+
}
52+
}
53+
54+
for (int it = first; it < lines.Count && lines[it].Number <= endLineNumber; ++it)
55+
yield return lines[it];
56+
}
57+
}
58+
}

SharedProject/Impl/CoverageColour/GlyphMargin/CoverageLineGlyphTag.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
using FineCodeCoverage.Engine.Model;
1+
using FineCodeCoverage.Engine.Cobertura;
2+
using FineCodeCoverage.Engine.Model;
23
using Microsoft.VisualStudio.Text.Editor;
34

45
namespace FineCodeCoverage.Impl
56
{
67
internal class CoverageLineGlyphTag : IGlyphTag
78
{
8-
public CoverageLine CoverageLine { get; }
9+
public Line CoverageLine { get; }
910

10-
public CoverageLineGlyphTag(CoverageLine coverageLine)
11+
public CoverageLineGlyphTag(Line coverageLine)
1112
{
1213
CoverageLine = coverageLine;
1314
}

SharedProject/Impl/CoverageColour/GlyphMargin/CoverageLineGlyphTagger.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace FineCodeCoverage.Impl
88
{
99
internal class CoverageLineGlyphTagger : CoverageLineTaggerBase<CoverageLineGlyphTag>, IListener<RefreshCoverageGlyphsMessage>
1010
{
11-
public CoverageLineGlyphTagger(ITextBuffer textBuffer, Dictionary<string, List<CoverageLine>> lastCoverageLines) : base(textBuffer, lastCoverageLines)
11+
public CoverageLineGlyphTagger(ITextBuffer textBuffer, SharedProject.Core.Model.FileLineCoverage lastCoverageLines) : base(textBuffer, lastCoverageLines)
1212
{
1313
}
1414

@@ -17,7 +17,7 @@ public void Handle(RefreshCoverageGlyphsMessage message)
1717
RaiseTagsChanged();
1818
}
1919

20-
protected override TagSpan<CoverageLineGlyphTag> GetTagSpan(CoverageLine coverageLine, SnapshotSpan span)
20+
protected override TagSpan<CoverageLineGlyphTag> GetTagSpan(Engine.Cobertura.Line coverageLine, SnapshotSpan span)
2121
{
2222
return new TagSpan<CoverageLineGlyphTag>(span, new CoverageLineGlyphTag(coverageLine));
2323
}

SharedProject/Impl/CoverageColour/GlyphMargin/CoverageLineGlyphTaggerProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected override void NewCoverageLinesMessageReceived()
4141
});
4242
}
4343

44-
protected override CoverageLineGlyphTagger CreateTagger(ITextBuffer textBuffer, Dictionary<string, List<CoverageLine>> lastCoverageLines)
44+
protected override CoverageLineGlyphTagger CreateTagger(ITextBuffer textBuffer, SharedProject.Core.Model.FileLineCoverage lastCoverageLines)
4545
{
4646
return new CoverageLineGlyphTagger(textBuffer, lastCoverageLines);
4747
}

SharedProject/Impl/CoverageColour/MarginBase/CoverageLineTaggerBase.cs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using FineCodeCoverage.Engine.Model;
33
using Microsoft.VisualStudio.Text;
44
using Microsoft.VisualStudio.Text.Tagging;
5+
using SharedProject.Core.Model;
56
using System;
67
using System.Collections.Generic;
78
using System.Linq;
@@ -11,11 +12,11 @@ namespace FineCodeCoverage.Impl
1112
internal abstract class CoverageLineTaggerBase<TTag> : ICoverageLineTagger<TTag> where TTag : ITag
1213
{
1314
private readonly ITextBuffer _textBuffer;
14-
private Dictionary<string, List<CoverageLine>> coverageLines;
15+
private FileLineCoverage coverageLines;
1516

1617
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
1718

18-
public CoverageLineTaggerBase(ITextBuffer textBuffer, Dictionary<string, List<CoverageLine>> lastCoverageLines)
19+
public CoverageLineTaggerBase(ITextBuffer textBuffer, FileLineCoverage lastCoverageLines)
1920
{
2021
_textBuffer = textBuffer;
2122
coverageLines = lastCoverageLines;
@@ -32,15 +33,8 @@ protected virtual void RaiseTagsChanged()
3233
TagsChanged?.Invoke(this, spanEventArgs);
3334
}
3435

35-
private IEnumerable<CoverageLine> GetApplicableLines(string filePath, int startLineNumber, int endLineNumber)
36-
{
37-
if (coverageLines.TryGetValue(filePath, out var lines))
38-
return lines.AsParallel()
39-
.Where(x => x.Line.Number >= startLineNumber && x.Line.Number <= endLineNumber)
40-
.ToArray();
41-
42-
return Enumerable.Empty<CoverageLine>();
43-
}
36+
private IEnumerable<Engine.Cobertura.Line> GetApplicableLines(string filePath, int startLineNumber, int endLineNumber)
37+
=> coverageLines.GetLines(filePath, startLineNumber, endLineNumber).ToArray();
4438

4539
public void Handle(NewCoverageLinesMessage message)
4640
{
@@ -86,6 +80,6 @@ protected virtual void AddTags(NormalizedSnapshotSpanCollection spans, List<ITag
8680
}
8781
}
8882

89-
protected abstract TagSpan<TTag> GetTagSpan(CoverageLine coverageLine, SnapshotSpan span);
83+
protected abstract TagSpan<TTag> GetTagSpan(Engine.Cobertura.Line coverageLine, SnapshotSpan span);
9084
}
9185
}

0 commit comments

Comments
 (0)