CompositeWorkItem
A CompositeWorkItem represents a test suite and
encapsulates the execution of the suite as well
as all its child tests.
using NUnit.Compatibility;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal.Commands;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
namespace NUnit.Framework.Internal.Execution
{
public class CompositeWorkItem : WorkItem
{
private class WorkItemOrderComparer : IComparer<WorkItem>
{
public int Compare(WorkItem x, WorkItem y)
{
int num = 2147483647;
int value = 2147483647;
if (x.Test.Properties.ContainsKey("Order"))
num = (int)x.Test.Properties["Order"][0];
if (y.Test.Properties.ContainsKey("Order"))
value = (int)y.Test.Properties["Order"][0];
return num.CompareTo(value);
}
}
private TestSuite _suite;
private TestSuiteResult _suiteResult;
private ITestFilter _childFilter;
private TestCommand _setupCommand;
private TestCommand _teardownCommand;
private List<WorkItem> _children;
private int _countOrder;
private CountdownEvent _childTestCountdown;
private object _completionLock = new object();
private object cancelLock = new object();
public List<WorkItem> Children {
get {
return _children;
}
private set {
_children = value;
}
}
public CompositeWorkItem(TestSuite suite, ITestFilter childFilter)
: base(suite)
{
_suite = suite;
_suiteResult = (base.Result as TestSuiteResult);
_childFilter = childFilter;
_countOrder = 0;
}
protected override void PerformWork()
{
InitializeSetUpAndTearDownCommands();
if (!CheckForCancellation()) {
if (base.Test.RunState != RunState.Explicit || _childFilter.IsExplicitMatch(base.Test)) {
switch (base.Test.RunState) {
default:
base.Result.SetResult(ResultState.Success);
CreateChildWorkItems();
if (_children.Count > 0) {
PerformOneTimeSetUp();
if (!CheckForCancellation()) {
switch (base.Result.ResultState.Status) {
case TestStatus.Passed:
RunChildren();
return;
case TestStatus.Inconclusive:
case TestStatus.Skipped:
case TestStatus.Failed:
SkipChildren(_suite, base.Result.ResultState.WithSite(FailureSite.Parent), "OneTimeSetUp: " + base.Result.Message);
break;
}
}
if (base.Context.ExecutionStatus != TestExecutionStatus.AbortRequested)
PerformOneTimeTearDown();
}
break;
case RunState.Skipped:
SkipFixture(ResultState.Skipped, GetSkipReason(), null);
break;
case RunState.Ignored:
SkipFixture(ResultState.Ignored, GetSkipReason(), null);
break;
case RunState.NotRunnable:
SkipFixture(ResultState.NotRunnable, GetSkipReason(), GetProviderStackTrace());
break;
}
} else
SkipFixture(ResultState.Explicit, GetSkipReason(), null);
}
WorkItemComplete();
}
private bool CheckForCancellation()
{
if (base.Context.ExecutionStatus != 0) {
base.Result.SetResult(ResultState.Cancelled, "Test cancelled by user");
return true;
}
return false;
}
private void InitializeSetUpAndTearDownCommands()
{
List<SetUpTearDownItem> list = (_suite.TypeInfo != null) ? CommandBuilder.BuildSetUpTearDownList(_suite.TypeInfo.Type, typeof(OneTimeSetUpAttribute), typeof(OneTimeTearDownAttribute)) : new List<SetUpTearDownItem>();
List<TestActionItem> list2 = new List<TestActionItem>();
foreach (ITestAction action in base.Actions) {
bool flag = (action.Targets & ActionTargets.Suite) == ActionTargets.Suite || (action.Targets == ActionTargets.Default && !(base.Test is ParameterizedMethodSuite));
bool num = (action.Targets & ActionTargets.Test) == ActionTargets.Test && !(base.Test is ParameterizedMethodSuite);
if (flag)
list2.Add(new TestActionItem(action));
if (num)
base.Context.UpstreamActions.Add(action);
}
_setupCommand = CommandBuilder.MakeOneTimeSetUpCommand(_suite, list, list2);
_teardownCommand = CommandBuilder.MakeOneTimeTearDownCommand(_suite, list, list2);
}
private void PerformOneTimeSetUp()
{
try {
_setupCommand.Execute(base.Context);
base.Context.UpdateContextFromEnvironment();
} catch (Exception ex) {
Exception ex2 = ex;
if (ex2 is NUnitException || ex2 is TargetInvocationException)
ex2 = ex2.InnerException;
base.Result.RecordException(ex2, FailureSite.SetUp);
}
}
private void RunChildren()
{
int num = _children.Count;
if (num == 0)
throw new InvalidOperationException("RunChildren called but item has no children");
_childTestCountdown = new CountdownEvent(num);
foreach (WorkItem child in _children) {
if (CheckForCancellation())
break;
child.Completed += OnChildCompleted;
child.InitializeContext(new TestExecutionContext(base.Context));
base.Context.Dispatcher.Dispatch(child);
num--;
}
if (num > 0) {
while (num-- > 0) {
CountDownChildTest();
}
}
}
private void CreateChildWorkItems()
{
_children = new List<WorkItem>();
foreach (ITest test in _suite.Tests) {
if (_childFilter.Pass(test)) {
WorkItem workItem = WorkItem.CreateWorkItem(test, _childFilter);
workItem.WorkerId = base.WorkerId;
if (workItem.TargetApartment == ApartmentState.Unknown && base.TargetApartment != ApartmentState.Unknown)
workItem.TargetApartment = base.TargetApartment;
if (test.Properties.ContainsKey("Order")) {
_children.Insert(0, workItem);
_countOrder++;
} else
_children.Add(workItem);
}
}
if (_countOrder != 0)
SortChildren();
}
private void SortChildren()
{
_children.Sort(0, _countOrder, new WorkItemOrderComparer());
}
private void SkipFixture(ResultState resultState, string message, string stackTrace)
{
base.Result.SetResult(resultState.WithSite(FailureSite.SetUp), message, StackFilter.Filter(stackTrace));
SkipChildren(_suite, resultState.WithSite(FailureSite.Parent), "OneTimeSetUp: " + message);
}
private void SkipChildren(TestSuite suite, ResultState resultState, string message)
{
foreach (Test test in suite.Tests) {
if (_childFilter.Pass(test)) {
TestResult testResult = test.MakeTestResult();
testResult.SetResult(resultState, message);
_suiteResult.AddResult(testResult);
base.Context.Listener.TestFinished(testResult);
if (test.IsSuite)
SkipChildren((TestSuite)test, resultState, message);
}
}
}
private void PerformOneTimeTearDown()
{
base.Context.EstablishExecutionEnvironment();
_teardownCommand.Execute(base.Context);
}
private string GetSkipReason()
{
return (string)base.Test.Properties.Get("_SKIPREASON");
}
private string GetProviderStackTrace()
{
return (string)base.Test.Properties.Get("_PROVIDERSTACKTRACE");
}
private void OnChildCompleted(object sender, EventArgs e)
{
lock (_completionLock) {
WorkItem workItem = sender as WorkItem;
if (workItem != null) {
workItem.Completed -= OnChildCompleted;
_suiteResult.AddResult(workItem.Result);
if (base.Context.StopOnError && workItem.Result.ResultState.Status == TestStatus.Failed)
base.Context.ExecutionStatus = TestExecutionStatus.StopRequested;
CountDownChildTest();
}
}
}
private void CountDownChildTest()
{
_childTestCountdown.Signal();
if (_childTestCountdown.CurrentCount == 0) {
if (base.Context.ExecutionStatus != TestExecutionStatus.AbortRequested)
PerformOneTimeTearDown();
foreach (ITestResult child in _suiteResult.Children) {
if (child.ResultState == ResultState.Cancelled) {
base.Result.SetResult(ResultState.Cancelled, "Cancelled by user");
break;
}
}
WorkItemComplete();
}
}
private static bool IsStaticClass(Type type)
{
if (TypeExtensions.GetTypeInfo(type).IsAbstract)
return TypeExtensions.GetTypeInfo(type).IsSealed;
return false;
}
public override void Cancel(bool force)
{
lock (cancelLock) {
if (_children != null) {
foreach (WorkItem child in _children) {
TestExecutionContext context = child.Context;
if (context != null)
context.ExecutionStatus = ((!force) ? TestExecutionStatus.StopRequested : TestExecutionStatus.AbortRequested);
if (child.State == WorkItemState.Running)
child.Cancel(force);
}
}
}
}
}
}