Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Hönel committed Feb 21, 2019
2 parents f17491a + ec0db45 commit 8f45678
Show file tree
Hide file tree
Showing 28 changed files with 483 additions and 111 deletions.
38 changes: 32 additions & 6 deletions GitDensity/Density/Hunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ private Hunk ComputeLinesAddedAndDeleted()
public Boolean RepresentsNewEmptyFile =>
this.OldLineStart == 0u && this.OldNumberOfLines == 0u && this.NewLineStart == 0u && this.NewNumberOfLines == 0u && this.Patch == String.Empty;

/// <summary>
/// An override for <see cref="HunksForPatch(PatchEntryChanges, DirectoryInfo, DirectoryInfo)"/>
/// that uses a dummy directory. Use this method only when you do not have any
/// reason to access or rely on a valid <see cref="Hunk.SourceFilePath"/> or
/// <see cref="Hunk.TargetFilePath"/> (useful for purely virtual use-cases when
/// no access to the underlying file is needed).
/// </summary>
/// <param name="pec"></param>
/// <returns></returns>
public static IEnumerable<Hunk> HunksForPatch(PatchEntryChanges pec)
{
var dummyDir = new DirectoryInfo(Path.GetTempPath());
return Hunk.HunksForPatch(pec, dummyDir, dummyDir);
}

/// <summary>
/// Returns an <see cref="IEnumerable{Hunk}"/> containing all hunks
/// for the given <see cref="PatchEntryChanges"/>.
Expand All @@ -150,13 +165,15 @@ public static IEnumerable<Hunk> HunksForPatch(PatchEntryChanges pec, DirectoryIn
String fullSourcePath, fullTargetPath;
Exception hunkPathException;

// First condition is an empty patch that is usually the result from adding a new, empty file.
// We will only return one empty Hunk for this case.
// Second condition is a pure Move/Rename (then there's no real diff).
// Third condition is a deletion of a whole file.
// First condition is an empty patch that is usually the result from adding a new, empty, diffable file.
// Second condition is a pure Move/Rename (then there's no real diff, i.e. no added/del'd lines).
// Third condition is a deletion of a whole, empty, diffable file.
//
// We will only return one empty Hunk for this case. This is important as all methods expect
// at least one Hunk from this enumeration, even if it's empty (check references).
if ((pec.Mode == Mode.NonExecutableFile && pec.OldMode == Mode.Nonexistent && pec.LinesAdded == 0)
|| (pec.Status == ChangeKind.Renamed && pec.LinesAdded == 0 && pec.LinesDeleted == 0)
|| (pec.Status == ChangeKind.Deleted && pec.Mode == Mode.Nonexistent))
|| (pec.Status == ChangeKind.Deleted && pec.Mode == Mode.Nonexistent && pec.LinesDeleted == 0))
{
if (!Hunk.TryGetHunkPaths(
pairSourceDirectory, pairTargetDirectory,
Expand Down Expand Up @@ -215,7 +232,7 @@ public static IEnumerable<Hunk> HunksForPatch(PatchEntryChanges pec, DirectoryIn
/// directories and filenames. However, sometimes these contain invalid chars. In that
/// case, this method will resort to manually concatenating these and return false; true,
/// otherwise.
/// A warning is logged using the <see cref="Hunk"/>'s logger.
/// A warning is logged using the <see cref="Hunk"/>'s <see cref="logger"/>.
/// </summary>
/// <param name="pairSourceDirectory"></param>
/// <param name="pairTargetDirectory"></param>
Expand Down Expand Up @@ -255,6 +272,15 @@ protected static Boolean TryGetHunkPaths(
}
}

/// <summary>
/// Issues a warning using the <see cref="logger"/>, when, for some reason,
/// the method <see cref="TryGetHunkPaths(DirectoryInfo, DirectoryInfo, string, string, out string, out string, out Exception)"/> fails to obtain the <see cref="Hunk"/>'s paths.
/// </summary>
/// <param name="ex"></param>
/// <param name="pairSourceDirectory"></param>
/// <param name="pairTargetDirectory"></param>
/// <param name="hunkSourcePath"></param>
/// <param name="hunkTargetPath"></param>
protected static void WarnAboutBrokenHunkPaths(
Exception ex,
DirectoryInfo pairSourceDirectory, DirectoryInfo pairTargetDirectory,
Expand Down
8 changes: 4 additions & 4 deletions GitDensity/GitDensity.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\LibGit2Sharp.NativeBinaries.1.0.210\build\net461\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\packages\LibGit2Sharp.NativeBinaries.1.0.210\build\net461\LibGit2Sharp.NativeBinaries.props')" />
<Import Project="..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
Expand Down Expand Up @@ -56,8 +56,8 @@
<Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<HintPath>..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
</Reference>
<Reference Include="LibGit2Sharp, Version=0.25.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
<HintPath>..\packages\LibGit2Sharp.0.25.0\lib\netstandard2.0\LibGit2Sharp.dll</HintPath>
<Reference Include="LibGit2Sharp, Version=0.26.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
<HintPath>..\packages\LibGit2Sharp.0.26.0\lib\net46\LibGit2Sharp.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
Expand Down Expand Up @@ -210,9 +210,9 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\LibGit2Sharp.NativeBinaries.1.0.210\build\net461\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\LibGit2Sharp.NativeBinaries.1.0.210\build\net461\LibGit2Sharp.NativeBinaries.props'))" />
<Error Condition="!Exists('..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets'))" />
<Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.109.1\build\net46\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.109.1\build\net46\System.Data.SQLite.Core.targets'))" />
<Error Condition="!Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props'))" />
</Target>
<Import Project="..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" />
<Import Project="..\packages\System.Data.SQLite.Core.1.0.109.1\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.109.1\build\net46\System.Data.SQLite.Core.targets')" />
Expand Down
69 changes: 68 additions & 1 deletion GitDensity/Similarity/TextBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
/// ---------------------------------------------------------------------------------
///
using GitDensity.Density;
using LibGit2Sharp;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand All @@ -38,7 +39,7 @@ public enum TextBlockType
/// Represents a block of text where the block consists of lines and their
/// line numbers.
/// </summary>
internal class TextBlock : IEquatable<TextBlock>, ICloneable
public class TextBlock : IEquatable<TextBlock>, ICloneable
{
protected IDictionary<UInt32, Line> linesWithLineNumber;

Expand Down Expand Up @@ -351,5 +352,71 @@ public object Clone()
tb.AddLines(this.LinesWithNumber.Select(kv => kv.Value.Clone() as Line));
return tb;
}

/// <summary>
/// Using <see cref="TextBlock"/>s, this method counts the net- and gross-amount
/// of lines added and deleted across all <see cref="Hunk"/>s of a <see cref="PatchEntryChanges"/> entity.
/// Uses <see cref="RemoveEmptyLinesAndComments()"/> to count the net-affected lines.
/// </summary>
/// <param name="pec"></param>
/// <param name="linesAddedGross">Amount of lines added across all hunks.</param>
/// <param name="linesDeletedGross">Amount of lines deleted across all hunks.</param>
/// <param name="linesAddedWithoutEmptyOrComments">Amount of lines added net across
/// all hunks. This count is equal to or lower than linesAddedGross, as empty lines
/// and comments are removed.</param>
/// <param name="linesDeletedWithoutEmptyOrComments">Amount of lines deleted net
/// across all hunks. This count is equal to or lower than linesDeletedGross, as empty
/// lines and comments are not considered in the deleted lines.</param>
public static void CountLinesInPatch(PatchEntryChanges pec,
out UInt32 linesAddedGross,
out UInt32 linesDeletedGross,
out UInt32 linesAddedWithoutEmptyOrComments,
out UInt32 linesDeletedWithoutEmptyOrComments)
{
var hunks = Hunk.HunksForPatch(pec);

var tbsAdded = hunks.Select(hunk => new TextBlock(hunk, TextBlockType.New)).ToList();
var tbsDeleted = hunks.Select(hunk => new TextBlock(hunk, TextBlockType.Old)).ToList();

linesAddedGross = (UInt32)tbsAdded.Sum(tb => tb.LinesAdded);
linesDeletedGross = (UInt32)tbsDeleted.Sum(tb => tb.LinesDeleted);

linesAddedWithoutEmptyOrComments = (UInt32)tbsAdded
.Select(tb => tb.RemoveEmptyLinesAndComments())
.Sum(tb => tb.LinesAdded);
linesDeletedWithoutEmptyOrComments = (UInt32)tbsDeleted
.Select(tb => tb.RemoveEmptyLinesAndComments())
.Sum(tb => tb.LinesDeleted);
}

/// <summary>
/// Uses <see cref="CountLinesInPatch(PatchEntryChanges, out uint, out uint, out uint, out uint)"/> to aggregate the line-counts for a list of <see cref="PatchEntryChanges"/>.
/// This is useful if multiple changes are to be considered. This is the case for
/// e.g. counting all lines across all modified/renamed files. Please see the documentation
/// for the referenced method.
/// </summary>
/// <param name="pecs"></param>
/// <param name="linesAddedGross"></param>
/// <param name="linesDeletedGross"></param>
/// <param name="linesAddedWithoutEmptyOrComments"></param>
/// <param name="linesDeletedWithoutEmptyOrComments"></param>
public static void CountLinesInAllPatches(IEnumerable<PatchEntryChanges> pecs,
out UInt32 linesAddedGross,
out UInt32 linesDeletedGross,
out UInt32 linesAddedWithoutEmptyOrComments,
out UInt32 linesDeletedWithoutEmptyOrComments)
{
linesAddedGross = linesDeletedGross = linesAddedWithoutEmptyOrComments = linesDeletedWithoutEmptyOrComments = 0u;

foreach (var pec in pecs)
{
TextBlock.CountLinesInPatch(
pec, out uint add, out uint del, out uint addNoC, out uint delNoC);
linesAddedGross += add;
linesDeletedGross += del;
linesAddedWithoutEmptyOrComments += addNoC;
linesDeletedWithoutEmptyOrComments += delNoC;
}
}
}
}
4 changes: 2 additions & 2 deletions GitDensity/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<package id="F23.StringSimilarity" version="3.0.0" targetFramework="net461" />
<package id="FluentNHibernate" version="2.1.2" targetFramework="net461" />
<package id="Iesi.Collections" version="4.0.4" targetFramework="net461" />
<package id="LibGit2Sharp" version="0.25.0" targetFramework="net461" />
<package id="LibGit2Sharp.NativeBinaries" version="1.0.210" targetFramework="net461" />
<package id="LibGit2Sharp" version="0.26.0" targetFramework="net461" />
<package id="LibGit2Sharp.NativeBinaries" version="2.0.267" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Abstractions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Binder" version="2.1.1" targetFramework="net461" />
Expand Down
5 changes: 5 additions & 0 deletions GitDensityTests/GitDensityTests.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props')" />
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
Expand Down Expand Up @@ -39,6 +40,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="LibGit2Sharp, Version=0.26.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
<HintPath>..\packages\LibGit2Sharp.0.26.0\lib\net46\LibGit2Sharp.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
Expand Down Expand Up @@ -75,6 +79,7 @@
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets'))" />
<Error Condition="!Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\LibGit2Sharp.NativeBinaries.2.0.267\build\net46\LibGit2Sharp.NativeBinaries.props'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" />
</Project>
77 changes: 77 additions & 0 deletions GitDensityTests/HunkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,30 @@
///
/// ---------------------------------------------------------------------------------
///
using GitDensity.Density;
using GitDensity.Similarity;
using LibGit2Sharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Util.Density;
using Util.Extensions;

namespace GitDensityTests
{
[TestClass]
public class HunkTests
{
public static DirectoryInfo SolutionDirectory
=> new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Locati‌​on)).Parent.Parent.Parent;


[TestMethod]
public void TestPatchSplit()
{
Expand Down Expand Up @@ -90,5 +101,71 @@ public void TestPatchSplitMultiLines()
Assert.AreEqual("-deleted line\n" +
"yo", hunks[1].Patch);
}

[TestMethod]
public void TestHunkGetLines()
{
using (var span = new Util.GitCommitSpan(SolutionDirectory.FullName.OpenRepository()))
{
// Has additions and deletions, also within comments
var comm1 = span.Where(c => c.Sha.StartsWith("6f18a54", StringComparison.OrdinalIgnoreCase)).First();
//// Has mostly additions but also (single-line) comments we wanna remove
//var comm2 = span.Where(c => c.Sha.StartsWith("f7574a4", StringComparison.OrdinalIgnoreCase)).First();

var pair = CommitPair.FromChild(comm1, span.Repository);
// Each change corresponds to a modified file:
var changes = pair.RelevantTreeChanges.Where(rtc => rtc.Status == ChangeKind.Modified);

// Let's look at 'IMetricsAnalyzer':
var patch = pair.Patch[changes.Where(c => c.Path.EndsWith("IMetricsAnalyzer.cs")).First().Path];

TextBlock.CountLinesInPatch(
patch, out uint add, out uint del, out uint addNoC, out uint delNoC);

Assert.AreEqual(7u, add);
Assert.AreEqual(3u, del);
Assert.AreEqual(2u, addNoC);
Assert.AreEqual(1u, delNoC);


// Now assert that this commit does not have any pure adds/renames:
changes = pair.RelevantTreeChanges.Where(rtc => rtc.Status == ChangeKind.Added || rtc.Status == ChangeKind.Renamed);
TextBlock.CountLinesInAllPatches(
changes.Select(c => pair.Patch[c.Path]), out add, out del, out addNoC, out delNoC);

Assert.AreEqual(0u, add);
Assert.AreEqual(0u, del);
Assert.AreEqual(0u, addNoC);
Assert.AreEqual(0u, delNoC);

// .. also pure deletes:
changes = pair.RelevantTreeChanges.Where(rtc => rtc.Status == ChangeKind.Deleted);
Assert.IsTrue(!changes.Any());
TextBlock.CountLinesInAllPatches(
changes.Select(c => pair.Patch[c.OldPath]), out add, out del, out addNoC, out delNoC);

Assert.AreEqual(0u, add);
Assert.AreEqual(0u, del);
Assert.AreEqual(0u, addNoC);
Assert.AreEqual(0u, delNoC);


//////////////////////////// Let's check a deleted file:
comm1 = span.Where(c => c.Sha.StartsWith("03e2779", StringComparison.OrdinalIgnoreCase)).First();
pair = CommitPair.FromChild(comm1, span.Repository);
changes = pair.RelevantTreeChanges.Where(rtc => rtc.Status == ChangeKind.Deleted);

Assert.AreEqual(3, changes.Count());

// Per file, only 2 lines are not comments!
TextBlock.CountLinesInAllPatches(
changes.Select(c => pair.Patch[c.Path]), out add, out del, out addNoC, out delNoC);

Assert.AreEqual(0u, add);
Assert.IsTrue(del >= 90u); // didn't count it, but roughly 3x30
Assert.AreEqual(0u, addNoC);
Assert.AreEqual(6u, delNoC);
}
}
}
}
2 changes: 2 additions & 0 deletions GitDensityTests/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="LibGit2Sharp" version="0.26.0" targetFramework="net461" />
<package id="LibGit2Sharp.NativeBinaries" version="2.0.267" targetFramework="net461" />
<package id="MSTest.TestAdapter" version="1.3.2" targetFramework="net461" />
<package id="MSTest.TestFramework" version="1.3.2" targetFramework="net461" />
</packages>
Loading

0 comments on commit 8f45678

Please sign in to comment.