Skip to content
This repository has been archived by the owner on Jan 14, 2021. It is now read-only.

Commit

Permalink
make FinallyDelegate more resilient regarding unhandled exceptions (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
lewurm authored and marek-safar committed Nov 14, 2017
1 parent 764656c commit a8bef89
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
27 changes: 24 additions & 3 deletions NUnitLite-1.0.0/src/framework/FinallyDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,18 @@
using System.Threading;
using NUnit.Framework.Api;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;

namespace NUnit.Framework.Internal
{
[Serializable]
class Container : ILogicalThreadAffinative {
public string testName;
public Container(string testName) {
this.testName = testName;
}
}

public class FinallyDelegate
{
// If our test spawns a thread that throws, we will bubble
Expand All @@ -49,19 +58,31 @@ public class FinallyDelegate
// so we need a stack of finally delegate continuations
Stack<Tuple<TestExecutionContext, long, TestResult>> testStack;

Dictionary<string, TestResult> lookupTable;

private static readonly string CONTEXT_KEY = "TestResultName";

public FinallyDelegate () {
this.testStack = new Stack<Tuple<TestExecutionContext, long, TestResult>>();
this.lookupTable = new Dictionary<string, TestResult>();
}

public void Set (TestExecutionContext context, long startTicks, TestResult result) {
var frame = new Tuple<TestExecutionContext, long, TestResult>(context, startTicks, result);

/* keep name in LogicalCallContext, because this will be inherited by
* Threads spawned by the test case */
CallContext.SetData(CONTEXT_KEY, new Container(result.Test.FullName));

this.lookupTable.Add(result.Test.FullName, result);
this.testStack.Push(frame);
}

public void HandleUnhandledExc (Exception ex) {
TestExecutionContext context = this.testStack.Peek().Item1;
context.CurrentResult.RecordException(ex);
context.CurrentResult.ThreadCrashFail = true;
Container c = (Container) CallContext.GetData(CONTEXT_KEY);
TestResult result = this.lookupTable [c.testName];
result.RecordException(ex);
result.ThreadCrashFail = true;
}

public void Complete () {
Expand Down
9 changes: 9 additions & 0 deletions NUnitLite-1.0.0/src/framework/Internal/WorkItems/WorkItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ private void RunTestWithTimeout(int timeout)
#endif

private void RunTest()
{
/* using a separate ExecutionContext for every test case,
* guarantees us to have a dedicated "namespace" for the
* LogicalCallContext per testcase */
ExecutionContext ec = ExecutionContext.Capture();
ExecutionContext.Run(ec, DispatchWork, null);
}

private void DispatchWork(object o)
{
_context.CurrentTest = this.Test;
_context.CurrentResult = this.Result;
Expand Down

0 comments on commit a8bef89

Please sign in to comment.