Nested exceptions in xunit1 class start/finish
This commit is contained in:
Родитель
336dd8a511
Коммит
9759e69ae6
|
@ -50,17 +50,14 @@ namespace Xunit
|
|||
SendTestCaseMessagesWhenAppropriate(null);
|
||||
|
||||
bool @continue = true;
|
||||
XmlNode failure;
|
||||
if ((failure = xml.SelectSingleNode("failure")) != null)
|
||||
XmlNode failureNode;
|
||||
if ((failureNode = xml.SelectSingleNode("failure")) != null)
|
||||
{
|
||||
// exception-type was added in xunit 1.1
|
||||
var attribute = failure.Attributes["exception-type"];
|
||||
var exceptionType = attribute != null ? attribute.Value : null;
|
||||
var message = failure.SelectSingleNode("message").InnerText;
|
||||
var stackTrace = failure.SelectSingleNode("stack-trace").InnerText;
|
||||
var failureInformation = Xunit1ExceptionUtility.ConvertToFailureInformation(failureNode);
|
||||
|
||||
var errorMessage = new ErrorMessage(new[] {exceptionType}, new[] {message}, new[] {stackTrace},
|
||||
new[] {-1});
|
||||
var errorMessage = new ErrorMessage(failureInformation.ExceptionTypes,
|
||||
failureInformation.Messages, failureInformation.StackTraces,
|
||||
failureInformation.ExceptionParentIndices);
|
||||
@continue = messageSink.OnMessage(errorMessage);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Xunit
|
||||
{
|
||||
internal static class Xunit1ExceptionUtility
|
||||
{
|
||||
static readonly Regex NestedMessagesRegex = new Regex(@"-*\s*(?<type>.*?) :\s*(?<message>.*?)((\r\n-)|\z)",
|
||||
RegexOptions.ExplicitCapture | RegexOptions.Multiline | RegexOptions.Singleline);
|
||||
static readonly Regex NestedStackTracesRegex = new Regex(@"\r*\n----- Inner Stack Trace -----\r*\n", RegexOptions.Compiled);
|
||||
|
||||
public static IFailureInformation ConvertToFailureInformation(XmlNode failureNode)
|
||||
{
|
||||
var exceptionTypeAttribute = failureNode.Attributes["exception-type"];
|
||||
var exceptionType = exceptionTypeAttribute != null ? exceptionTypeAttribute.Value : string.Empty;
|
||||
var message = failureNode.SelectSingleNode("message").InnerText;
|
||||
var stackTrace = failureNode.SelectSingleNode("stack-trace").InnerText;
|
||||
|
||||
return ConvertToFailureInformation(exceptionType, message, stackTrace);
|
||||
}
|
||||
|
||||
static IFailureInformation ConvertToFailureInformation(string outermostExceptionType, string nestedExceptionMessages, string nestedStackTraces)
|
||||
{
|
||||
var failureInformation = new FailureInformation();
|
||||
|
||||
var exceptionTypes = new List<string>();
|
||||
var messages = new List<string>();
|
||||
|
||||
var match = NestedMessagesRegex.Match(nestedExceptionMessages);
|
||||
for (int i = 0; match.Success; i++, match = match.NextMatch())
|
||||
{
|
||||
exceptionTypes.Add(match.Groups["type"].Value);
|
||||
messages.Add(match.Groups["message"].Value);
|
||||
}
|
||||
|
||||
if (exceptionTypes.Count == 0)
|
||||
{
|
||||
exceptionTypes.Add(outermostExceptionType);
|
||||
messages.Add(nestedExceptionMessages);
|
||||
}
|
||||
|
||||
failureInformation.ExceptionTypes = exceptionTypes.ToArray();
|
||||
failureInformation.Messages = messages.ToArray();
|
||||
failureInformation.StackTraces = NestedStackTracesRegex.Split(nestedStackTraces);
|
||||
|
||||
failureInformation.ExceptionParentIndices = new int[failureInformation.StackTraces.Length];
|
||||
for (int i = 0; i < failureInformation.ExceptionParentIndices.Length; i++)
|
||||
failureInformation.ExceptionParentIndices[i] = i - 1;
|
||||
|
||||
return failureInformation;
|
||||
}
|
||||
|
||||
class FailureInformation : IFailureInformation
|
||||
{
|
||||
public string[] ExceptionTypes { get; set; }
|
||||
public string[] Messages { get; set; }
|
||||
public string[] StackTraces { get; set; }
|
||||
public int[] ExceptionParentIndices { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -142,6 +142,7 @@
|
|||
<Link>Frameworks\Messages\TestStarting.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Frameworks\TestFrameworkOptions.cs" />
|
||||
<Compile Include="Frameworks\v1\Xunit1ExceptionUtility.cs" />
|
||||
<Compile Include="Frameworks\v2\XunitDiscoveryOptions.cs" />
|
||||
<Compile Include="Frameworks\v2\XunitExecutionOptions.cs" />
|
||||
<Compile Include="Project\XunitFilters.cs" />
|
||||
|
|
|
@ -467,6 +467,124 @@ public class Xunit1Tests
|
|||
Assert.Equal("Cannot use a test class as its own fixture data", errorMessage.Messages.Single());
|
||||
Assert.Equal(exception.StackTrace, errorMessage.StackTraces.Single());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedExceptionsThrownDuringClassStart_ResultsInErrorMessage()
|
||||
{
|
||||
var testCollection = new Xunit1TestCollection("AssemblyName.dll");
|
||||
var testCases = new[] {
|
||||
new Xunit1TestCase("assembly", "failingtype", "passingmethod", "failingtype.passingmethod") { TestCollection = testCollection }
|
||||
};
|
||||
var exception = GetNestedExceptions();
|
||||
var xunit1 = new TestableXunit1("AssemblyName.dll", "ConfigFile.config");
|
||||
xunit1.Executor.TestFrameworkDisplayName.Returns("Test framework display name");
|
||||
xunit1.Executor
|
||||
.When(x => x.RunTests("failingtype", Arg.Any<List<string>>(),
|
||||
Arg.Any<ICallbackEventHandler>()))
|
||||
.Do(callInfo =>
|
||||
{
|
||||
var callback = callInfo.Arg<ICallbackEventHandler>();
|
||||
callback.RaiseCallbackEvent("<start name='failingtype.passingmethod' type='failingtype' method='passingmethod'/>");
|
||||
callback.RaiseCallbackEvent("<test name='failingtype.passingmethod' type='failingtype' method='passingmethod' result='Pass' time='1.000'/>");
|
||||
callback.RaiseCallbackEvent(string.Format("<class name='failingtype' time='0.000' total='0' passed='1' failed='1' skipped='0'><failure exception-type='System.InvalidOperationException'><message>{0}</message><stack-trace><![CDATA[{1}]]></stack-trace></failure></class>", GetMessage(exception), GetStackTrace(exception)));
|
||||
});
|
||||
var sink = new SpyMessageSink<ITestAssemblyFinished>();
|
||||
|
||||
xunit1.Run(testCases, sink);
|
||||
sink.Finished.WaitOne();
|
||||
|
||||
var errorMessage = Assert.Single(sink.Messages.OfType<IErrorMessage>());
|
||||
Assert.Equal(exception.GetType().FullName, errorMessage.ExceptionTypes[0]);
|
||||
Assert.Equal(exception.InnerException.GetType().FullName, errorMessage.ExceptionTypes[1]);
|
||||
Assert.Equal(exception.Message, errorMessage.Messages[0]);
|
||||
Assert.Equal(exception.InnerException.Message, errorMessage.Messages[1]);
|
||||
Assert.Equal(exception.StackTrace, errorMessage.StackTraces[0]);
|
||||
Assert.Equal(exception.InnerException.StackTrace, errorMessage.StackTraces[1]);
|
||||
}
|
||||
|
||||
private Exception GetNestedExceptions()
|
||||
{
|
||||
try
|
||||
{
|
||||
ThrowOuterException();
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowOuterException()
|
||||
{
|
||||
try
|
||||
{
|
||||
ThrowInnerException();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException("Message from outer exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowInnerException()
|
||||
{
|
||||
throw new DivideByZeroException();
|
||||
}
|
||||
|
||||
// From xunit1's ExceptionUtility
|
||||
private static string GetMessage(Exception ex)
|
||||
{
|
||||
return GetMessage(ex, 0);
|
||||
}
|
||||
|
||||
static string GetMessage(Exception ex, int level)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (level > 0)
|
||||
{
|
||||
for (int idx = 0; idx < level; idx++)
|
||||
result += "----";
|
||||
|
||||
result += " ";
|
||||
}
|
||||
|
||||
// We won't have any AssertExceptions - we're testing failure in class start/finish
|
||||
//if (!(ex is AssertException))
|
||||
result += ex.GetType().FullName + " : ";
|
||||
|
||||
result += ex.Message;
|
||||
|
||||
if (ex.InnerException != null)
|
||||
result = result + Environment.NewLine + GetMessage(ex.InnerException, level + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const string RETHROW_MARKER = "$$RethrowMarker$$";
|
||||
|
||||
private static string GetStackTrace(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
return "";
|
||||
|
||||
string result = ex.StackTrace;
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
int idx = result.IndexOf(RETHROW_MARKER);
|
||||
if (idx >= 0)
|
||||
result = result.Substring(0, idx);
|
||||
}
|
||||
|
||||
if (ex.InnerException != null)
|
||||
result = result + Environment.NewLine +
|
||||
"----- Inner Stack Trace -----" + Environment.NewLine +
|
||||
GetStackTrace(ex.InnerException);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class TestableXunit1 : Xunit1
|
||||
|
|
Загрузка…
Ссылка в новой задаче