Skip to content

Commit 127ed8c

Browse files
committed
LowerBound compare function to return int to allow for early exit. Added tests
1 parent d9d162d commit 127ed8c

File tree

6 files changed

+94
-86
lines changed

6 files changed

+94
-86
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using FineCodeCoverage.Engine.Model;
5+
using NUnit.Framework;
6+
7+
namespace FineCodeCoverageTests
8+
{
9+
internal class FileLineCoverage_Tests
10+
{
11+
[TestCaseSource(nameof(Cases))]
12+
public void GetLines_Test(IEnumerable<int> lineNumbers, int startLineNumber, int endLineNumber, IEnumerable<int> expectedLineNumbers)
13+
{
14+
var fileLineCoverage = new FileLineCoverage();
15+
fileLineCoverage.Add("fp", lineNumbers.Select(n => new FineCodeCoverage.Engine.Cobertura.Line { Number = n }));
16+
fileLineCoverage.Completed();
17+
18+
var lines = fileLineCoverage.GetLines("fp", startLineNumber, endLineNumber);
19+
Assert.That(lines.Select(l => l.Number), Is.EqualTo(expectedLineNumbers));
20+
}
21+
22+
static object[] Cases =
23+
{
24+
new object[] { new int[] { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}, 19, 20, new int[]{ 19,20} },
25+
new object[] { new int[] { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}, 12, 13, new int[]{ 12,13} },
26+
new object[] { new int[] { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}, 6, 7, new int[]{ 6,7} },
27+
new object[] {Enumerable.Empty<int>(), 0, 4,Enumerable.Empty<int>() },
28+
new object[] { new int[] { 3,2,1}, 0, 4, new int[]{ 1,2,3} },
29+
new object[] { new int[] { 3,2,1}, 0, 3, new int[]{ 1,2,3} },
30+
new object[] { new int[] { 3,2,1}, 1, 2, new int[]{ 1,2} },
31+
new object[] { new int[] { 3,2,1}, 2, 2, new int[]{ 2} },
32+
new object[] { new int[] { 3,2,1}, 4, 5, Enumerable.Empty<int>() }
33+
};
34+
}
35+
}

FineCodeCoverageTests/FineCodeCoverageTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
<Compile Include="CoverageToolOutput_Tests\SolutionFolderProvider_Tests.cs" />
115115
<Compile Include="AppOptionsProvider_Tests.cs" />
116116
<Compile Include="CoverageUtilManager_Tests.cs" />
117+
<Compile Include="FileLineCoverage_Tests.cs" />
117118
<Compile Include="MsCodeCoverage\ShimCopier_Tests.cs" />
118119
<Compile Include="MsCodeCoverage\TemplatedRunSettingsService_Tests.cs" />
119120
<Compile Include="MsCodeCoverage\CustomRunSettingsTemplateProvider_Tests.cs" />

SharedProject/Core/Cobertura/CoberturaUtil.cs

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
using System.Collections.Generic;
55
using FineCodeCoverage.Engine.Model;
66
using System.ComponentModel.Composition;
7-
using System.IO;
8-
using System.Windows.Documents;
9-
using System;
107

118
namespace FineCodeCoverage.Engine.Cobertura
129
{
@@ -27,65 +24,22 @@ private CoverageReport LoadReport(string xmlFile)
2724
}
2825
}
2926

30-
//private void CoverageXmlFileToJsonFile(string xmlFile, string jsonFile, bool formattedJson = false)
31-
//{
32-
// var xmlText = File.ReadAllText(xmlFile);
33-
// var jsonText = CoverageXmlTextToJsonText(xmlText, formattedJson);
34-
// File.WriteAllText(jsonFile, jsonText);
35-
//}
36-
37-
//private string CoverageXmlTextToJsonText(string xmlText, bool formattedJson = false)
38-
//{
39-
// long count = 0;
40-
41-
// var xmlLines = xmlText
42-
// .Split('\r', '\n')
43-
// .Select(x => x.Trim())
44-
// .Where(x => !x.StartsWith("<?xml"))
45-
// .Where(x => !x.StartsWith("<!DOCTYPE"))
46-
// .Where(x => !x.StartsWith("<sources>") && !x.StartsWith("</sources>") && !x.StartsWith("<source>"))
47-
// .Where(x => !x.StartsWith("<packages>") && !x.StartsWith("</packages>"))
48-
// .Where(x => !x.StartsWith("<classes>") && !x.StartsWith("</classes>"))
49-
// .Where(x => !x.StartsWith("<methods>") && !x.StartsWith("</methods>"))
50-
// .Where(x => !x.StartsWith("<lines>") && !x.StartsWith("</lines>"))
51-
// .Select(x => x
52-
// .Replace("<package ", $"<packages id=\"p{count++}\" json:Array='true' ").Replace("</package>", "</packages>")
53-
// .Replace("<class ", $"<classes id=\"c{count++}\" json:Array='true' ").Replace("</class>", "</classes>")
54-
// .Replace("<method ", $"<methods id=\"m{count++}\" json:Array='true' ").Replace("</method>", "</methods>")
55-
// .Replace("<line ", $"<lines id=\"l{count++}\" json:Array='true' ").Replace("</line>", "</lines>")
56-
// );
57-
58-
// var processedXmlText = string
59-
// .Join(Environment.NewLine, xmlLines)
60-
// .Replace("<coverage ", "<coverage xmlns:json='http://james.newtonking.com/projects/json' ");
61-
62-
// var xmlDocument = new XmlDocument();
63-
// xmlDocument.LoadXml(processedXmlText);
64-
65-
// string jsonText = JsonConvert
66-
// .SerializeXmlNode(xmlDocument, formattedJson ? Newtonsoft.Json.Formatting.Indented : Newtonsoft.Json.Formatting.None, true)
67-
// .Replace("\"@", "\"");
68-
69-
// return jsonText;
70-
//}
71-
7227
public FileLineCoverage ProcessCoberturaXml(string xmlFile)
7328
{
74-
var coverageLines = new FileLineCoverage();
29+
var fileLineCoverage = new FileLineCoverage();
7530

7631
coverageReport = LoadReport(xmlFile);
7732

7833
foreach (var package in coverageReport.Packages.Package)
7934
{
8035
foreach (var classs in package.Classes.Class)
8136
{
82-
coverageLines.Add(classs.Filename, classs.Lines.Line);
83-
37+
fileLineCoverage.Add(classs.Filename, classs.Lines.Line);
8438
}
8539
}
8640

87-
coverageLines.Completed();
88-
return coverageLines;
41+
fileLineCoverage.Completed();
42+
return fileLineCoverage;
8943
}
9044

9145
public string[] GetSourceFiles(string assemblyName, string qualifiedClassName, int file)
Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using FineCodeCoverage.Engine.Cobertura;
1+
using FineCodeCoverage.Core.Utilities;
2+
using FineCodeCoverage.Engine.Cobertura;
23
using System;
34
using System.Collections.Generic;
4-
using System.Linq;
55

66
namespace FineCodeCoverage.Engine.Model
77
{
@@ -10,7 +10,6 @@ internal class FileLineCoverage
1010
{
1111
private Dictionary<string, List<Line>> m_coverageLines = new Dictionary<string, List<Line>>(StringComparer.OrdinalIgnoreCase);
1212

13-
1413
public void Add(string filename, IEnumerable<Line> lines)
1514
{
1615
if (!m_coverageLines.TryGetValue(filename, out var fileCoverageLines))
@@ -22,7 +21,7 @@ public void Add(string filename, IEnumerable<Line> lines)
2221
fileCoverageLines.AddRange(lines);
2322
}
2423

25-
internal void Completed()
24+
public void Completed()
2625
{
2726
foreach (var lines in m_coverageLines.Values)
2827
lines.Sort((a, b) => a.Number - b.Number);
@@ -31,41 +30,17 @@ internal void Completed()
3130
public IEnumerable<Line> GetLines(string filePath, int startLineNumber, int endLineNumber)
3231
{
3332
if (!m_coverageLines.TryGetValue(filePath, out var lines))
34-
return Enumerable.Empty<Line>();
35-
36-
int first = lines.LowerBound(line => line.Number < startLineNumber);
37-
int last = first;
38-
while (last < lines.Count && lines[last].Number <= endLineNumber)
39-
++last;
40-
41-
return lines.GetRange(first, last - first);
42-
}
43-
}
33+
yield break;
4434

45-
public static class ListExtensions
46-
{
47-
// Returns the index of the first element in a sorted list where the comparison function is false
48-
public static int LowerBound<T>(this IList<T> list, Func<T, bool> compare)
49-
{
50-
// binary search to find the first line
51-
int first = 0;
52-
int count = list.Count;
53-
while (count > 0)
35+
int first = lines.LowerBound(line => startLineNumber - line.Number);
36+
if (first != -1)
5437
{
55-
int step = count / 2;
56-
int it = first + step;
57-
if (compare(list[it]))
58-
{
59-
first = ++it;
60-
count -= step + 1;
61-
}
62-
else
63-
{
64-
count = step;
65-
}
38+
for (int it = first; it < lines.Count && lines[it].Number <= endLineNumber; ++it)
39+
yield return lines[it];
6640
}
67-
68-
return first;
41+
6942
}
7043
}
44+
45+
7146
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace FineCodeCoverage.Core.Utilities
5+
{
6+
public static class ListExtensions
7+
{
8+
// To be performed on a sorted list
9+
// Returns -1 for empty list or when all elements are outside the lower bounds
10+
// Compare fn to return 0 for element considered the lower bound
11+
// > 0 for lower bound greater than element
12+
13+
public static int LowerBound<T>(this IList<T> list, Func<T, int> compare)
14+
{
15+
int first = 0;
16+
int count = list.Count;
17+
if (count == 0) return -1;
18+
19+
while (count > 0)
20+
{
21+
int step = count / 2;
22+
int index = first + step;
23+
var result = compare(list[index]);
24+
if (result == 0)
25+
{
26+
return index;
27+
}
28+
else if (result > 0)
29+
{
30+
first = ++index;
31+
count -= step + 1;
32+
}
33+
else
34+
{
35+
count = step;
36+
}
37+
}
38+
39+
return first != list.Count ? first : -1;
40+
}
41+
}
42+
}

SharedProject/SharedProject.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ISolutionEvents.cs" />
149149
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\IZipFile.cs" />
150150
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\LinqExtensions.cs" />
151+
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ListExtensions.cs" />
151152
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\MEF.cs" />
152153
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ProcessResponseProcessor.cs" />
153154
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ProcessUtil.cs" />

0 commit comments

Comments
 (0)