Permalink
Browse files

Adding nested exceptions and their types to the XML report, improving…

… code that cleans our lines from stack traces. Closes #137
  • Loading branch information...
1 parent 31e3615 commit e1d117a17408ff3966e8ff8d749219583e6f42ad @agross agross committed Mar 7, 2013
@@ -216,6 +216,10 @@ static void RenderError(XmlWriter reportBuilder, ExceptionResult exception)
reportBuilder.WriteStartElement("error");
+ reportBuilder.WriteStartElement("type");
+ reportBuilder.WriteCData(exception.FullTypeName);
+ reportBuilder.WriteEndElement();
+
reportBuilder.WriteStartElement("message");
reportBuilder.WriteCData(exception.Message);
reportBuilder.WriteEndElement();
@@ -224,6 +228,11 @@ static void RenderError(XmlWriter reportBuilder, ExceptionResult exception)
reportBuilder.WriteCData(exception.StackTrace);
reportBuilder.WriteEndElement();
+ if (exception.InnerExceptionResult != null)
+ {
+ RenderError(reportBuilder, exception.InnerExceptionResult);
+ }
+
reportBuilder.WriteEndElement();
}
}
@@ -1,10 +1,11 @@
using System;
+using System.Reflection;
using Machine.Specifications;
+#if CLEAN_EXCEPTION_STACK_TRACE
using SomeProject.Specs;
-
namespace SomeProject.Specs
{
static class Throw
@@ -25,7 +26,6 @@ public static Exception Exception()
}
}
-#if CLEAN_EXCEPTION_STACK_TRACE
namespace Machine.Specifications.Specs
{
[Subject(typeof(ExceptionResult))]
@@ -38,8 +38,33 @@ public class When_framework_stack_trace_lines_are_filtered
It should_remove_framework_stack_lines =
() => Result.StackTrace.ShouldNotContain(" Machine.Specifications.");
+ It should_remove_framework_stack_lines_from_the_string_representation =
+ () => Result.ToString().ShouldNotContain(" Machine.Specifications.");
+
It should_keep_user_stack_lines =
() => Result.StackTrace.ShouldContain(" SomeProject.Specs.Throw.Exception");
}
+
+ [Subject(typeof(ExceptionResult))]
+ public class When_the_actual_exception_is_wrapped_in_a_TargetInvocationException
+ {
+ static ExceptionResult Result;
+
+ Because of = () => { Result = new ExceptionResult(new TargetInvocationException(new Exception("inner"))); };
+
+ It should_only_take_the_inner_exception_into_account =
+ () => Result.FullTypeName.ShouldEqual(typeof(Exception).FullName);
+ }
+
+ [Subject(typeof(ExceptionResult))]
+ public class When_a_TargetInvocationException_is_wrapped
+ {
+ static ExceptionResult Result;
+
+ Because of = () => { Result = new ExceptionResult(new Exception("outer", new TargetInvocationException(new Exception("inner")))); };
+
+ It should_keep_the_exception =
+ () => Result.InnerExceptionResult.FullTypeName.ShouldEqual(typeof(TargetInvocationException).FullName);
+ }
}
#endif
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
using System.Text.RegularExpressions;
namespace Machine.Specifications
@@ -15,32 +18,55 @@ public enum Status
[Serializable]
public class ExceptionResult
{
- readonly string _toString;
-
public string FullTypeName { get; private set; }
public string TypeName { get; private set; }
public string Message { get; private set; }
public string StackTrace { get; private set; }
public ExceptionResult InnerExceptionResult { get; private set; }
- public ExceptionResult(Exception exception)
+ public ExceptionResult(Exception exception) : this(exception, true)
+ {
+ }
+
+ ExceptionResult(Exception exception, bool outermost)
{
+#if CLEAN_EXCEPTION_STACK_TRACE
+ if (outermost && exception is TargetInvocationException)
+ {
+ exception = exception.InnerException;
+ }
+#endif
+
FullTypeName = exception.GetType().FullName;
TypeName = exception.GetType().Name;
Message = exception.Message;
StackTrace = FilterStackTrace(exception.StackTrace);
if (exception.InnerException != null)
{
- InnerExceptionResult = new ExceptionResult(exception.InnerException);
+ InnerExceptionResult = new ExceptionResult(exception.InnerException, false);
}
-
- _toString = exception.ToString();
}
public override string ToString()
{
- return _toString;
+ var message = new StringBuilder();
+ message.Append(FullTypeName);
+
+ if (!string.IsNullOrEmpty(Message))
+ {
+ message.AppendFormat(": {0}", Message);
+ }
+ if (InnerExceptionResult != null)
+ {
+ message.AppendFormat(" ---> {0}{1} --- End of inner exception stack trace ---", InnerExceptionResult, Environment.NewLine);
+ }
+ if (StackTrace != null)
+ {
+ message.Append(Environment.NewLine + StackTrace);
+ }
+
+ return message.ToString();
}
#region Borrowed from XUnit to clean up the stack trace, licened under MS-PL
@@ -49,16 +75,18 @@ public override string ToString()
/// <summary>
/// A description of the regular expression:
///
- /// \w+\sMachine\.Specifications
+ /// ^\s+\w+\sMachine\.Specifications
+ /// Beginning of string
+ /// Whitespace, one or more repetitions
/// Alphanumeric, one or more repetitions
/// Whitespace
/// Machine
/// Literal .
/// Specifications
/// Literal .
/// </summary>
- static Regex FrameworkStackLine = new Regex("\\w+\\sMachine\\.Specifications\\.",
- RegexOptions.CultureInvariant | RegexOptions.Compiled);
+ static readonly Regex FrameworkStackLine = new Regex("^\\s+\\w+\\sMachine\\.Specifications\\.",
+ RegexOptions.CultureInvariant | RegexOptions.Compiled);
/// <summary>
/// Filters the stack trace to remove all lines that occur within the testing framework.
@@ -68,43 +96,21 @@ public override string ToString()
static string FilterStackTrace(string stackTrace)
{
if (stackTrace == null)
- return null;
+ return null;
- List<string> results = new List<string>();
-
- foreach (string line in SplitLines(stackTrace))
- {
- string trimmedLine = line.TrimStart();
- if (!IsFrameworkStackFrame(trimmedLine))
- results.Add(line);
- }
+ var lines = stackTrace
+ .Split(new[] {Environment.NewLine}, StringSplitOptions.None)
+ .Where(line => !IsFrameworkStackFrame(line))
+ .ToArray();
- return string.Join(Environment.NewLine, results.ToArray());
+ return string.Join(Environment.NewLine, lines);
}
static bool IsFrameworkStackFrame(string trimmedLine)
{
// Anything in the Machine.Specifications namespace
return FrameworkStackLine.IsMatch(trimmedLine);
}
-
- // Our own custom String.Split because Silverlight/CoreCLR doesn't support the version we were using
- static IEnumerable<string> SplitLines(string input)
- {
- while (true)
- {
- int index = input.IndexOf(Environment.NewLine);
-
- if (index < 0)
- {
- yield return input;
- break;
- }
-
- yield return input.Substring(0, index);
- input = input.Substring(index + Environment.NewLine.Length);
- }
- }
#else
// Do not change the line at all if you are not going to clean it
static string FilterStackTrace(string stackTrace)
@@ -222,4 +228,4 @@ public static Result Supplement(Result result, string supplementName, IDictionar
return new Result(result, supplementName, supplement);
}
}
-}
+}
@@ -1,8 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Runtime.Serialization;
-using System.Text;
namespace Machine.Specifications
{
@@ -34,33 +31,4 @@ public SpecificationUsageException(string message, Exception inner) : base(messa
{
}
}
-
- [Serializable]
- public class SpecificationVerificationException : Exception
- {
- //
- // For guidelines regarding the creation of new exception types, see
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
- // and
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
- //
-
- public SpecificationVerificationException()
- {
- }
-
- public SpecificationVerificationException(string message) : base(message)
- {
- }
-
- public SpecificationVerificationException(string message, Exception inner) : base(message, inner)
- {
- }
-
- protected SpecificationVerificationException(
- SerializationInfo info,
- StreamingContext context) : base(info, context)
- {
- }
- }
}

0 comments on commit e1d117a

Please sign in to comment.