Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2sharp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2015-04-29 00:09:47 +0300
committernulltoken <emeric.fermas@gmail.com>2015-04-29 00:09:47 +0300
commit8febb35461b3391851df7ec9ca25c34313e70a9c (patch)
tree77a24b6a6ecda62c3c8858edfaaf85409447e7c4
parent7f0cc1e3d4eb99999991de06831c5b7d0a25cf03 (diff)
parent983ce4928390d89b77aba1d9ccb043699652d282 (diff)
Merge pull request #1026 from libgit2/jamill/set_error
Try harder to format error messages
-rw-r--r--LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj1
-rw-r--r--LibGit2Sharp.Tests/SetErrorFixture.cs182
-rw-r--r--LibGit2Sharp/Core/NativeMethods.cs2
-rw-r--r--LibGit2Sharp/Core/Proxy.cs61
4 files changed, 244 insertions, 2 deletions
diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index c477d4f8..904c427d 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -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" />
diff --git a/LibGit2Sharp.Tests/SetErrorFixture.cs b/LibGit2Sharp.Tests/SetErrorFixture.cs
new file mode 100644
index 00000000..62bdeab8
--- /dev/null
+++ b/LibGit2Sharp.Tests/SetErrorFixture.cs
@@ -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
+
+ }
+}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index e74e250b..b71d4708 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -85,7 +85,7 @@ namespace LibGit2Sharp.Core
[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();
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index 2ba1be49..a7b4d6ef 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text;
using System.Threading;
using LibGit2Sharp.Core.Handles;
using LibGit2Sharp.Handlers;
@@ -23,7 +24,7 @@ namespace LibGit2Sharp.Core
}
else
{
- NativeMethods.giterr_set_str(error_class, exception.Message);
+ NativeMethods.giterr_set_str(error_class, ErrorMessageFromException(exception));
}
}
@@ -32,6 +33,64 @@ namespace LibGit2Sharp.Core
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_