Skip to content

Abstract LibGit2Sharp away in testing context #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Binary file added Lib/MoQ/Moq.dll
Binary file not shown.
5,768 changes: 5,768 additions & 0 deletions Lib/MoQ/Moq.xml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
<DocumentationFile />
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Lib\MoQ\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="xunit">
Expand All @@ -53,6 +57,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MockedRepositoryFixture.cs" />
<Compile Include="ConfigurationFixture.cs" />
<Compile Include="AttributesFixture.cs" />
<Compile Include="CommitAncestorFixture.cs" />
Expand Down
71 changes: 71 additions & 0 deletions LibGit2Sharp.Tests/MockedRepositoryFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Collections.Generic;
using System;
using System.Linq;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Moq;

namespace LibGit2Sharp.Tests
{
// This fixture shows how one can mock the IRepository when writing an application against LibGit2Sharp.
// The application we want to test is simulated by the CommitCounter class (see below), which takes an IRepository,
// and whose role is to compute and return the number of commits in the given repository.
public class MockedRepositoryFixture : BaseFixture
{
// In this test, we pass to CommitCounter a concrete instance of the Repository. It means we will end up calling the concrete Repository
// during the test run.
[Fact]
public void CanCountCommitsWithConcreteRepository()
{
using (var repo = new Repository(BareTestRepoPath))
{
var commitCounter = new CommitCounter(repo);
Assert.Equal(7, commitCounter.NumberOfCommits);
}
}

// This test shows that CommitCounter can take a mocked instance of IRepository. It means we can test CommitCounter without
// relying on the concrete repository. We are testing CommitCounter in isolation.
[Fact]
public void CanCountCommitsWithMockedRepository()
{
var commitLog = Mock.Of<CommitLog>(cl => cl.GetEnumerator() == FakeCommitLog(17));
var repo = Mock.Of<IRepository>(r => r.Commits == commitLog);

var commitCounter = new CommitCounter(repo);
Assert.Equal(17, commitCounter.NumberOfCommits);
}

private static IEnumerator<Commit> FakeCommitLog(int size)
{
for (int i = 0; i < size; i++)
{
yield return FakeCommit(Guid.NewGuid().ToString());
}
}

private static Commit FakeCommit(string sha)
{
var commitMock = new Mock<Commit>();
commitMock.SetupGet(x => x.Sha).Returns(sha);

return commitMock.Object;
}

// Simulated external application ;)
private class CommitCounter
{
private readonly IRepository repo;

public CommitCounter(IRepository repo)
{
this.repo = repo;
}

public int NumberOfCommits
{
get { return repo.Commits.Count(); }
}
}
}
}
30 changes: 9 additions & 21 deletions LibGit2Sharp/Blob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public class Blob : GitObject
{
private readonly Repository repo;

/// <summary>
/// Needed for mocking purposes.
/// </summary>
protected Blob()
{ }

internal Blob(Repository repo, ObjectId id)
: base(id)
{
Expand All @@ -23,12 +29,12 @@ internal Blob(Repository repo, ObjectId id)
/// <summary>
/// Gets the size in bytes of the contents of a blob
/// </summary>
public int Size { get; set; }
public virtual int Size { get; set; }

/// <summary>
/// Gets the blob content in a <see cref="byte" /> array.
/// </summary>
public byte[] Content
public virtual byte[] Content
{
get
{
Expand All @@ -44,7 +50,7 @@ public byte[] Content
/// <summary>
/// Gets the blob content in a <see cref="Stream" />.
/// </summary>
public Stream ContentStream
public virtual Stream ContentStream
{
get
{
Expand All @@ -59,24 +65,6 @@ public Stream ContentStream
}
}

/// <summary>
/// Gets the blob content decoded as UTF-8.
/// </summary>
/// <returns></returns>
public string ContentAsUtf8()
{
return Encoding.UTF8.GetString(Content);
}

/// <summary>
/// Gets the blob content decoded as Unicode.
/// </summary>
/// <returns></returns>
public string ContentAsUnicode()
{
return Encoding.Unicode.GetString(Content);
}

internal static Blob BuildFromPtr(GitObjectSafeHandle obj, ObjectId id, Repository repo)
{
var blob = new Blob(repo, id)
Expand Down
30 changes: 30 additions & 0 deletions LibGit2Sharp/BlobExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Text;

namespace LibGit2Sharp
{
/// <summary>
/// Provides helper overloads to a <see cref = "Blob" />.
/// </summary>
public static class BlobExtensions
{
/// <summary>
/// Gets the blob content decoded as UTF-8.
/// </summary>
/// <param name="blob">The blob for which the content will be returned.</param>
/// <returns>Blob content as UTF-8</returns>
public static string ContentAsUtf8(this Blob blob)
{
return Encoding.UTF8.GetString(blob.Content);
}

/// <summary>
/// Gets the blob content decoded as Unicode.
/// </summary>
/// <param name="blob">The blob for which the content will be returned.</param>
/// <returns>Blob content as unicode.</returns>
public static string ContentAsUnicode(this Blob blob)
{
return Encoding.Unicode.GetString(blob.Content);
}
}
}
22 changes: 14 additions & 8 deletions LibGit2Sharp/Branch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public class Branch : ReferenceWrapper<Commit>
{
private readonly Lazy<Branch> trackedBranch;

/// <summary>
/// Needed for mocking purposes.
/// </summary>
protected Branch()
{ }

/// <summary>
/// Initializes a new instance of the <see cref = "Branch" /> class.
/// </summary>
Expand Down Expand Up @@ -47,7 +53,7 @@ private Branch(Repository repo, Reference reference, Func<Reference, string> can
/// </summary>
/// <param name = "relativePath">The relative path to the <see cref = "TreeEntry" /> from the <see cref = "Tip" /> working directory.</param>
/// <returns><c>null</c> if nothing has been found, the <see cref = "TreeEntry" /> otherwise.</returns>
public TreeEntry this[string relativePath]
public virtual TreeEntry this[string relativePath]
{
get
{
Expand All @@ -74,31 +80,31 @@ public virtual bool IsRemote
/// <summary>
/// Gets the remote branch which is connected to this local one.
/// </summary>
public Branch TrackedBranch
public virtual Branch TrackedBranch
{
get { return trackedBranch.Value; }
}

/// <summary>
/// Determines if this local branch is connected to a remote one.
/// </summary>
public bool IsTracking
public virtual bool IsTracking
{
get { return TrackedBranch != null; }
}

/// <summary>
/// Gets the number of commits, starting from the <see cref="Tip"/>, that have been performed on this local branch and aren't known from the remote one.
/// </summary>
public int AheadBy
public virtual int AheadBy
{
get { return IsTracking ? repo.Commits.QueryBy(new Filter { Since = Tip, Until = TrackedBranch }).Count() : 0; }
}

/// <summary>
/// Gets the number of commits that exist in the remote branch, on top of <see cref="Tip"/>, and aren't known from the local one.
/// </summary>
public int BehindBy
public virtual int BehindBy
{
get { return IsTracking ? repo.Commits.QueryBy(new Filter { Since = TrackedBranch, Until = Tip }).Count() : 0; }
}
Expand All @@ -109,23 +115,23 @@ public int BehindBy
/// <value>
/// <c>true</c> if this instance is the current branch; otherwise, <c>false</c>.
/// </value>
public bool IsCurrentRepositoryHead
public virtual bool IsCurrentRepositoryHead
{
get { return repo.Head == this; }
}

/// <summary>
/// Gets the <see cref="Commit"/> that this branch points to.
/// </summary>
public Commit Tip
public virtual Commit Tip
{
get { return TargetObject; }
}

/// <summary>
/// Gets the commits on this branch. (Starts walking from the References's target).
/// </summary>
public ICommitLog Commits
public virtual ICommitLog Commits
{
get { return repo.Commits.QueryBy(new Filter { Since = this }); }
}
Expand Down
16 changes: 11 additions & 5 deletions LibGit2Sharp/BranchCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public class BranchCollection : IEnumerable<Branch>
{
private readonly Repository repo;

/// <summary>
/// Needed for mocking purposes.
/// </summary>
protected BranchCollection()
{ }

/// <summary>
/// Initializes a new instance of the <see cref = "BranchCollection" /> class.
/// </summary>
Expand All @@ -26,7 +32,7 @@ internal BranchCollection(Repository repo)
/// <summary>
/// Gets the <see cref = "LibGit2Sharp.Branch" /> with the specified name.
/// </summary>
public Branch this[string name]
public virtual Branch this[string name]
{
get
{
Expand Down Expand Up @@ -69,7 +75,7 @@ private Branch BuildFromReferenceName(string canonicalName)
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>An <see cref = "IEnumerator{T}" /> object that can be used to iterate through the collection.</returns>
public IEnumerator<Branch> GetEnumerator()
public virtual IEnumerator<Branch> GetEnumerator()
{
return Libgit2UnsafeHelper
.ListAllBranchNames(repo.Handle, GitBranchType.GIT_BRANCH_LOCAL | GitBranchType.GIT_BRANCH_REMOTE)
Expand All @@ -95,7 +101,7 @@ IEnumerator IEnumerable.GetEnumerator()
/// <param name = "shaOrReferenceName">The target which can be sha or a canonical reference name.</param>
/// <param name = "allowOverwrite">True to allow silent overwriting a potentially existing branch, false otherwise.</param>
/// <returns></returns>
public Branch Add(string name, string shaOrReferenceName, bool allowOverwrite = false)
public virtual Branch Add(string name, string shaOrReferenceName, bool allowOverwrite = false)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");

Expand Down Expand Up @@ -128,7 +134,7 @@ public Branch Create(string name, string shaOrReferenceName, bool allowOverwrite
/// </summary>
/// <param name = "name">The name of the branch to delete.</param>
/// <param name = "isRemote">True if the provided <paramref name="name"/> is the name of a remote branch, false otherwise.</param>
public void Remove(string name, bool isRemote = false)
public virtual void Remove(string name, bool isRemote = false)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");

Expand Down Expand Up @@ -160,7 +166,7 @@ public void Delete(string name, bool isRemote = false)
///<param name = "newName">The new name of the existing branch should bear.</param>
///<param name = "allowOverwrite">True to allow silent overwriting a potentially existing branch, false otherwise.</param>
///<returns></returns>
public Branch Move(string currentName, string newName, bool allowOverwrite = false)
public virtual Branch Move(string currentName, string newName, bool allowOverwrite = false)
{
Ensure.ArgumentNotNullOrEmptyString(currentName, "currentName");
Ensure.ArgumentNotNullOrEmptyString(newName, "name");
Expand Down
14 changes: 10 additions & 4 deletions LibGit2Sharp/Changes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ public abstract class Changes
{
private readonly StringBuilder patchBuilder = new StringBuilder();

/// <summary>
/// Needed for mocking purposes.
/// </summary>
protected Changes()
{ }

internal void AppendToPatch(string patch)
{
patchBuilder.Append(patch);
Expand All @@ -17,24 +23,24 @@ internal void AppendToPatch(string patch)
/// <summary>
/// The number of lines added.
/// </summary>
public int LinesAdded { get; internal set; }
public virtual int LinesAdded { get; internal set; }

/// <summary>
/// The number of lines deleted.
/// </summary>
public int LinesDeleted { get; internal set; }
public virtual int LinesDeleted { get; internal set; }

/// <summary>
/// The patch corresponding to these changes.
/// </summary>
public string Patch
public virtual string Patch
{
get { return patchBuilder.ToString(); }
}

/// <summary>
/// Determines if at least one side of the comparison holds binary content.
/// </summary>
public bool IsBinaryComparison { get; protected set; }
public virtual bool IsBinaryComparison { get; protected set; }
}
}
Loading