Skip to content

Commit

Permalink
LowerBound compare function to return int to allow for early exit. Ad…
Browse files Browse the repository at this point in the history
…ded tests
  • Loading branch information
tonyhallett committed Oct 26, 2022
1 parent d9d162d commit 127ed8c
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 86 deletions.
35 changes: 35 additions & 0 deletions FineCodeCoverageTests/FileLineCoverage_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FineCodeCoverage.Engine.Model;
using NUnit.Framework;

namespace FineCodeCoverageTests
{
internal class FileLineCoverage_Tests
{
[TestCaseSource(nameof(Cases))]
public void GetLines_Test(IEnumerable<int> lineNumbers, int startLineNumber, int endLineNumber, IEnumerable<int> expectedLineNumbers)
{
var fileLineCoverage = new FileLineCoverage();
fileLineCoverage.Add("fp", lineNumbers.Select(n => new FineCodeCoverage.Engine.Cobertura.Line { Number = n }));
fileLineCoverage.Completed();

var lines = fileLineCoverage.GetLines("fp", startLineNumber, endLineNumber);
Assert.That(lines.Select(l => l.Number), Is.EqualTo(expectedLineNumbers));
}

static object[] Cases =
{
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} },
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} },
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} },
new object[] {Enumerable.Empty<int>(), 0, 4,Enumerable.Empty<int>() },
new object[] { new int[] { 3,2,1}, 0, 4, new int[]{ 1,2,3} },
new object[] { new int[] { 3,2,1}, 0, 3, new int[]{ 1,2,3} },
new object[] { new int[] { 3,2,1}, 1, 2, new int[]{ 1,2} },
new object[] { new int[] { 3,2,1}, 2, 2, new int[]{ 2} },
new object[] { new int[] { 3,2,1}, 4, 5, Enumerable.Empty<int>() }
};
}
}
1 change: 1 addition & 0 deletions FineCodeCoverageTests/FineCodeCoverageTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
<Compile Include="CoverageToolOutput_Tests\SolutionFolderProvider_Tests.cs" />
<Compile Include="AppOptionsProvider_Tests.cs" />
<Compile Include="CoverageUtilManager_Tests.cs" />
<Compile Include="FileLineCoverage_Tests.cs" />
<Compile Include="MsCodeCoverage\ShimCopier_Tests.cs" />
<Compile Include="MsCodeCoverage\TemplatedRunSettingsService_Tests.cs" />
<Compile Include="MsCodeCoverage\CustomRunSettingsTemplateProvider_Tests.cs" />
Expand Down
54 changes: 4 additions & 50 deletions SharedProject/Core/Cobertura/CoberturaUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
using System.Collections.Generic;
using FineCodeCoverage.Engine.Model;
using System.ComponentModel.Composition;
using System.IO;
using System.Windows.Documents;
using System;

namespace FineCodeCoverage.Engine.Cobertura
{
Expand All @@ -27,65 +24,22 @@ private CoverageReport LoadReport(string xmlFile)
}
}

//private void CoverageXmlFileToJsonFile(string xmlFile, string jsonFile, bool formattedJson = false)
//{
// var xmlText = File.ReadAllText(xmlFile);
// var jsonText = CoverageXmlTextToJsonText(xmlText, formattedJson);
// File.WriteAllText(jsonFile, jsonText);
//}

//private string CoverageXmlTextToJsonText(string xmlText, bool formattedJson = false)
//{
// long count = 0;

// var xmlLines = xmlText
// .Split('\r', '\n')
// .Select(x => x.Trim())
// .Where(x => !x.StartsWith("<?xml"))
// .Where(x => !x.StartsWith("<!DOCTYPE"))
// .Where(x => !x.StartsWith("<sources>") && !x.StartsWith("</sources>") && !x.StartsWith("<source>"))
// .Where(x => !x.StartsWith("<packages>") && !x.StartsWith("</packages>"))
// .Where(x => !x.StartsWith("<classes>") && !x.StartsWith("</classes>"))
// .Where(x => !x.StartsWith("<methods>") && !x.StartsWith("</methods>"))
// .Where(x => !x.StartsWith("<lines>") && !x.StartsWith("</lines>"))
// .Select(x => x
// .Replace("<package ", $"<packages id=\"p{count++}\" json:Array='true' ").Replace("</package>", "</packages>")
// .Replace("<class ", $"<classes id=\"c{count++}\" json:Array='true' ").Replace("</class>", "</classes>")
// .Replace("<method ", $"<methods id=\"m{count++}\" json:Array='true' ").Replace("</method>", "</methods>")
// .Replace("<line ", $"<lines id=\"l{count++}\" json:Array='true' ").Replace("</line>", "</lines>")
// );

// var processedXmlText = string
// .Join(Environment.NewLine, xmlLines)
// .Replace("<coverage ", "<coverage xmlns:json='http://james.newtonking.com/projects/json' ");

// var xmlDocument = new XmlDocument();
// xmlDocument.LoadXml(processedXmlText);

// string jsonText = JsonConvert
// .SerializeXmlNode(xmlDocument, formattedJson ? Newtonsoft.Json.Formatting.Indented : Newtonsoft.Json.Formatting.None, true)
// .Replace("\"@", "\"");

// return jsonText;
//}

public FileLineCoverage ProcessCoberturaXml(string xmlFile)
{
var coverageLines = new FileLineCoverage();
var fileLineCoverage = new FileLineCoverage();

coverageReport = LoadReport(xmlFile);

foreach (var package in coverageReport.Packages.Package)
{
foreach (var classs in package.Classes.Class)
{
coverageLines.Add(classs.Filename, classs.Lines.Line);

fileLineCoverage.Add(classs.Filename, classs.Lines.Line);
}
}

coverageLines.Completed();
return coverageLines;
fileLineCoverage.Completed();
return fileLineCoverage;
}

public string[] GetSourceFiles(string assemblyName, string qualifiedClassName, int file)
Expand Down
47 changes: 11 additions & 36 deletions SharedProject/Core/Model/FileLineCoverage.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using FineCodeCoverage.Engine.Cobertura;
using FineCodeCoverage.Core.Utilities;
using FineCodeCoverage.Engine.Cobertura;
using System;
using System.Collections.Generic;
using System.Linq;

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


public void Add(string filename, IEnumerable<Line> lines)
{
if (!m_coverageLines.TryGetValue(filename, out var fileCoverageLines))
Expand All @@ -22,7 +21,7 @@ public void Add(string filename, IEnumerable<Line> lines)
fileCoverageLines.AddRange(lines);
}

internal void Completed()
public void Completed()
{
foreach (var lines in m_coverageLines.Values)
lines.Sort((a, b) => a.Number - b.Number);
Expand All @@ -31,41 +30,17 @@ internal void Completed()
public IEnumerable<Line> GetLines(string filePath, int startLineNumber, int endLineNumber)
{
if (!m_coverageLines.TryGetValue(filePath, out var lines))
return Enumerable.Empty<Line>();

int first = lines.LowerBound(line => line.Number < startLineNumber);
int last = first;
while (last < lines.Count && lines[last].Number <= endLineNumber)
++last;

return lines.GetRange(first, last - first);
}
}
yield break;

public static class ListExtensions
{
// Returns the index of the first element in a sorted list where the comparison function is false
public static int LowerBound<T>(this IList<T> list, Func<T, bool> compare)
{
// binary search to find the first line
int first = 0;
int count = list.Count;
while (count > 0)
int first = lines.LowerBound(line => startLineNumber - line.Number);
if (first != -1)
{
int step = count / 2;
int it = first + step;
if (compare(list[it]))
{
first = ++it;
count -= step + 1;
}
else
{
count = step;
}
for (int it = first; it < lines.Count && lines[it].Number <= endLineNumber; ++it)
yield return lines[it];
}

return first;

}
}


}
42 changes: 42 additions & 0 deletions SharedProject/Core/Utilities/ListExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;

namespace FineCodeCoverage.Core.Utilities
{
public static class ListExtensions
{
// To be performed on a sorted list
// Returns -1 for empty list or when all elements are outside the lower bounds
// Compare fn to return 0 for element considered the lower bound
// > 0 for lower bound greater than element

public static int LowerBound<T>(this IList<T> list, Func<T, int> compare)
{
int first = 0;
int count = list.Count;
if (count == 0) return -1;

while (count > 0)
{
int step = count / 2;
int index = first + step;
var result = compare(list[index]);
if (result == 0)
{
return index;
}
else if (result > 0)
{
first = ++index;
count -= step + 1;
}
else
{
count = step;
}
}

return first != list.Count ? first : -1;
}
}
}
1 change: 1 addition & 0 deletions SharedProject/SharedProject.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ISolutionEvents.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\IZipFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\LinqExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ListExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\MEF.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ProcessResponseProcessor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core\Utilities\ProcessUtil.cs" />
Expand Down

0 comments on commit 127ed8c

Please sign in to comment.