1 // ***********************************************************************
2 // Copyright (c) 2010 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
30 using System.Globalization;
31 using System.Collections.Generic;
32 using System.Reflection;
35 namespace NUnit.Framework.Internal
38 /// ExceptionHelper provides static methods for working with exceptions
40 public class ExceptionHelper
42 #if !NET_4_5 && !PORTABLE && !SILVERLIGHT && !NETCF
43 private static readonly Action<Exception> PreserveStackTrace;
45 static ExceptionHelper()
47 var method = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic);
53 PreserveStackTrace = (Action<Exception>)Delegate.CreateDelegate(typeof(Action<Exception>), method);
56 catch (InvalidOperationException) { }
58 PreserveStackTrace = _ => { };
62 #if !NETCF && !SILVERLIGHT
64 /// Rethrows an exception, preserving its stack trace
66 /// <param name="exception">The exception to rethrow</param>
67 public static void Rethrow(Exception exception)
69 #if NET_4_5 || PORTABLE
70 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exception).Throw();
72 PreserveStackTrace(exception);
78 // TODO: Move to a utility class
80 /// Builds up a message, using the Message field of the specified exception
81 /// as well as any InnerExceptions.
83 /// <param name="exception">The exception.</param>
84 /// <returns>A combined message string.</returns>
85 public static string BuildMessage(Exception exception)
87 StringBuilder sb = new StringBuilder();
88 sb.AppendFormat(CultureInfo.CurrentCulture, "{0} : {1}", exception.GetType().ToString(), exception.Message);
90 foreach (Exception inner in FlattenExceptionHierarchy(exception))
92 sb.Append(NUnit.Env.NewLine);
93 sb.AppendFormat(CultureInfo.CurrentCulture, " ----> {0} : {1}", inner.GetType().ToString(), inner.Message);
100 /// Builds up a message, using the Message field of the specified exception
101 /// as well as any InnerExceptions.
103 /// <param name="exception">The exception.</param>
104 /// <returns>A combined stack trace.</returns>
105 public static string BuildStackTrace(Exception exception)
107 StringBuilder sb = new StringBuilder(GetStackTrace(exception));
109 foreach (Exception inner in FlattenExceptionHierarchy(exception))
111 sb.Append(NUnit.Env.NewLine);
113 sb.Append(inner.GetType().Name);
114 sb.Append(NUnit.Env.NewLine);
115 sb.Append(GetStackTrace(inner));
118 return sb.ToString();
122 /// Gets the stack trace of the exception.
124 /// <param name="exception">The exception.</param>
125 /// <returns>A string representation of the stack trace.</returns>
126 public static string GetStackTrace(Exception exception)
130 return exception.StackTrace;
134 return "No stack trace available";
138 private static List<Exception> FlattenExceptionHierarchy(Exception exception)
140 var result = new List<Exception>();
142 #if NET_4_0 || NET_4_5 || SILVERLIGHT || PORTABLE
143 if (exception is AggregateException)
145 var aggregateException = (exception as AggregateException);
146 result.AddRange(aggregateException.InnerExceptions);
148 foreach (var innerException in aggregateException.InnerExceptions)
149 result.AddRange(FlattenExceptionHierarchy(innerException));
153 if (exception.InnerException != null)
155 result.Add(exception.InnerException);
156 result.AddRange(FlattenExceptionHierarchy(exception.InnerException));