Skip to content

Commit

Permalink
Merge pull request #1026 from libgit2/jamill/set_error
Browse files Browse the repository at this point in the history
Try harder to format error messages
  • Loading branch information
nulltoken committed Apr 28, 2015
2 parents 7f0cc1e + 983ce49 commit 8febb35
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 2 deletions.
1 change: 1 addition & 0 deletions LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<Compile Include="RefSpecFixture.cs" />
<Compile Include="EqualityFixture.cs" />
<Compile Include="RevertFixture.cs" />
<Compile Include="SetErrorFixture.cs" />
<Compile Include="SignatureFixture.cs" />
<Compile Include="FilterBranchFixture.cs" />
<Compile Include="RemoveFixture.cs" />
Expand Down
182 changes: 182 additions & 0 deletions LibGit2Sharp.Tests/SetErrorFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
using System;
using System.IO;
using System.Text;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;

namespace LibGit2Sharp.Tests
{
public class SetErrorFixture : BaseFixture
{

private const string simpleExceptionMessage = "This is a simple exception message.";
private const string aggregateExceptionMessage = "This is aggregate exception.";
private const string outerExceptionMessage = "This is an outer exception.";
private const string innerExceptionMessage = "This is an inner exception.";
private const string innerExceptionMessage2 = "This is inner exception #2.";

private const string expectedInnerExceptionHeaderText = "Inner Exception:";
private const string expectedAggregateExceptionHeaderText = "Contained Exception:";
private const string expectedAggregateExceptionsHeaderText = "Contained Exceptions:";

[Fact]
public void FormatSimpleException()
{
Exception exceptionToThrow = new Exception(simpleExceptionMessage);
string expectedMessage = simpleExceptionMessage;

AssertExpectedExceptionMessage(expectedMessage, exceptionToThrow);
}

[Fact]
public void FormatExceptionWithInnerException()
{
Exception exceptionToThrow = new Exception(outerExceptionMessage, new Exception(innerExceptionMessage));

StringBuilder sb = new StringBuilder();
sb.AppendLine(outerExceptionMessage);
sb.AppendLine();
AppendIndentedLine(sb, expectedInnerExceptionHeaderText, 0);
AppendIndentedText(sb, innerExceptionMessage, 1);
string expectedMessage = sb.ToString();

AssertExpectedExceptionMessage(expectedMessage, exceptionToThrow);
}

[Fact]
public void FormatAggregateException()
{
Exception exceptionToThrow = new AggregateException(aggregateExceptionMessage, new Exception(innerExceptionMessage), new Exception(innerExceptionMessage2));

StringBuilder sb = new StringBuilder();
sb.AppendLine(aggregateExceptionMessage);
sb.AppendLine();

AppendIndentedLine(sb, expectedAggregateExceptionsHeaderText, 0);

AppendIndentedLine(sb, innerExceptionMessage, 1);
sb.AppendLine();

AppendIndentedText(sb, innerExceptionMessage2, 1);

string expectedMessage = sb.ToString();

AssertExpectedExceptionMessage(expectedMessage, exceptionToThrow);
}

private void AssertExpectedExceptionMessage(string expectedMessage, Exception exceptionToThrow)
{
Exception thrownException = null;

ObjectId id = new ObjectId("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

string repoPath = InitNewRepository();
using (var repo = new Repository(repoPath))
{
repo.ObjectDatabase.AddBackend(new ThrowingOdbBackend(exceptionToThrow), priority: 1);

try
{
repo.Lookup<Blob>(id);
}
catch (Exception ex)
{
thrownException = ex;
}
}

Assert.NotNull(thrownException);
Assert.Equal(expectedMessage, thrownException.Message);
}

private void AppendIndentedText(StringBuilder sb, string text, int indentLevel)
{
sb.AppendFormat("{0}{1}", IndentString(indentLevel), text);
}

private void AppendIndentedLine(StringBuilder sb, string text, int indentLevel)
{
sb.AppendFormat("{0}{1}{2}", IndentString(indentLevel), text, Environment.NewLine);
}

private string IndentString(int level)
{
return new string(' ', level * 4);
}

#region ThrowingOdbBackend

private class ThrowingOdbBackend : OdbBackend
{
private Exception exceptionToThrow;

public ThrowingOdbBackend(Exception exceptionToThrow)
{
this.exceptionToThrow = exceptionToThrow;
}

protected override OdbBackendOperations SupportedOperations
{
get
{
return OdbBackendOperations.Read |
OdbBackendOperations.ReadPrefix |
OdbBackendOperations.Write |
OdbBackendOperations.WriteStream |
OdbBackendOperations.Exists |
OdbBackendOperations.ExistsPrefix |
OdbBackendOperations.ForEach |
OdbBackendOperations.ReadHeader;
}
}

public override int Read(ObjectId oid, out UnmanagedMemoryStream data, out ObjectType objectType)
{
throw this.exceptionToThrow;
}

public override int ReadPrefix(string shortSha, out ObjectId id, out UnmanagedMemoryStream data, out ObjectType objectType)
{
throw this.exceptionToThrow;
}

public override int Write(ObjectId oid, Stream dataStream, long length, ObjectType objectType)
{
throw this.exceptionToThrow;
}

public override int WriteStream(long length, ObjectType objectType, out OdbBackendStream stream)
{
throw this.exceptionToThrow;
}

public override bool Exists(ObjectId oid)
{
throw this.exceptionToThrow;
}

public override int ExistsPrefix(string shortSha, out ObjectId found)
{
throw this.exceptionToThrow;
}

public override int ReadHeader(ObjectId oid, out int length, out ObjectType objectType)
{
throw this.exceptionToThrow;
}

public override int ReadStream(ObjectId oid, out OdbBackendStream stream)
{
throw this.exceptionToThrow;
}

public override int ForEach(ForEachCallback callback)
{
throw this.exceptionToThrow;
}
}

#endregion

}
}
2 changes: 1 addition & 1 deletion LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ static NativeMethods()
[DllImport(libgit2)]
internal static extern void giterr_set_str(
GitErrorCategory error_class,
string errorString);
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string errorString);

[DllImport(libgit2)]
internal static extern void giterr_set_oom();
Expand Down
61 changes: 60 additions & 1 deletion LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using LibGit2Sharp.Core.Handles;
using LibGit2Sharp.Handlers;
Expand All @@ -23,7 +24,7 @@ public static void giterr_set_str(GitErrorCategory error_class, Exception except
}
else
{
NativeMethods.giterr_set_str(error_class, exception.Message);
NativeMethods.giterr_set_str(error_class, ErrorMessageFromException(exception));
}
}

Expand All @@ -32,6 +33,64 @@ public static void giterr_set_str(GitErrorCategory error_class, String errorStri
NativeMethods.giterr_set_str(error_class, errorString);
}

/// <summary>
/// This method will take an exception and try to generate an error message
/// that captures the important messages of the error.
/// The formatting is a bit subjective.
/// </summary>
/// <param name="ex"></param>
/// <returns></returns>
public static string ErrorMessageFromException(Exception ex)
{
StringBuilder sb = new StringBuilder();
BuildErrorMessageFromException(sb, 0, ex);
return sb.ToString();
}

private static void BuildErrorMessageFromException(StringBuilder sb, int level, Exception ex)
{
string indent = new string(' ', level * 4);
sb.AppendFormat("{0}{1}", indent, ex.Message);

if (ex is AggregateException)
{
AggregateException aggregateException = ((AggregateException)ex).Flatten();

if (aggregateException.InnerExceptions.Count == 1)
{
sb.AppendLine();
sb.AppendLine();

sb.AppendFormat("{0}Contained Exception:{1}", indent, Environment.NewLine);
BuildErrorMessageFromException(sb, level + 1, aggregateException.InnerException);
}
else
{
sb.AppendLine();
sb.AppendLine();

sb.AppendFormat("{0}Contained Exceptions:{1}", indent, Environment.NewLine);
for (int i = 0; i < aggregateException.InnerExceptions.Count; i++)
{
if (i != 0)
{
sb.AppendLine();
sb.AppendLine();
}

BuildErrorMessageFromException(sb, level + 1, aggregateException.InnerExceptions[i]);
}
}
}
else if (ex.InnerException != null)
{
sb.AppendLine();
sb.AppendLine();
sb.AppendFormat("{0}Inner Exception:{1}", indent, Environment.NewLine);
BuildErrorMessageFromException(sb, level + 1, ex.InnerException);
}
}

#endregion

#region git_blame_
Expand Down

0 comments on commit 8febb35

Please sign in to comment.