#region Copyright (c) 2002-2003, James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole, Philip A. Craig
/************************************************************************************
'
' Copyright © 2002-2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole
' Copyright © 2000-2003 Philip A. Craig
'
' This software is provided 'as-is', without any express or implied warranty. In no
' event will the authors be held liable for any damages arising from the use of this
' software.
'
' Permission is granted to anyone to use this software for any purpose, including
' commercial applications, and to alter it and redistribute it freely, subject to the
' following restrictions:
'
' 1. The origin of this software must not be misrepresented; you must not claim that
' you wrote the original software. If you use this software in a product, an
' acknowledgment (see the following) in the product documentation is required.
'
' Portions Copyright © 2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole
' or Copyright © 2000-2003 Philip A. Craig
'
' 2. Altered source versions must be plainly marked as such, and must not be
' misrepresented as being the original software.
'
' 3. This notice may not be removed or altered from any source distribution.
'
'***********************************************************************************/
#endregion
namespace NUnit.Core
{
using System;
using System.Collections;
using System.Reflection;
///
/// Summary description for TestSuite.
///
///
[Serializable]
public class TestSuite : Test
{
private ArrayList tests = new ArrayList();
private MethodInfo fixtureSetUp;
private MethodInfo fixtureTearDown;
private object fixture;
private const string FIXTURE_SETUP_FAILED = "Fixture setup failed";
public TestSuite( string name ) : this( name, 0 ) { }
public TestSuite( string name, int assemblyKey )
: base( name, assemblyKey )
{
ShouldRun = true;
}
public void Sort()
{
this.Tests.Sort();
foreach( Test test in Tests )
{
TestSuite suite = test as TestSuite;
if ( suite != null )
suite.Sort();
}
}
public TestSuite( string parentSuiteName, string name )
: this( parentSuiteName, name, 0 ) { }
public TestSuite( string parentSuiteName, string name, int assemblyKey )
: base( parentSuiteName, name, assemblyKey )
{
ShouldRun = true;
}
protected internal virtual void Add(Test test)
{
if(test.ShouldRun)
{
test.ShouldRun = ShouldRun;
test.IgnoreReason = IgnoreReason;
}
tests.Add(test);
if (test.IsTestCase)
((TestCase) test).Suite = this;
}
protected internal virtual TestSuite CreateNewSuite(Type type)
{
int index = type.FullName.LastIndexOf( "." ) + 1;
string name = type.FullName.Substring( index );
return new TestSuite( type.Namespace, name, this.AssemblyKey);
}
public void Add(object fixture)
{
TestSuite testSuite = CreateNewSuite(fixture.GetType());
testSuite.fixture = fixture;
testSuite.fixtureSetUp = this.FindMethodByAttribute(fixture, typeof(NUnit.Framework.TestFixtureSetUpAttribute));
testSuite.fixtureTearDown = this.FindMethodByAttribute(fixture, typeof(NUnit.Framework.TestFixtureTearDownAttribute));
Add(testSuite);
Type ignoreMethodAttribute = typeof(NUnit.Framework.IgnoreAttribute);
object[] attributes = fixture.GetType().GetCustomAttributes(ignoreMethodAttribute, false);
if(attributes.Length == 1)
{
NUnit.Framework.IgnoreAttribute attr =
(NUnit.Framework.IgnoreAttribute)attributes[0];
testSuite.ShouldRun = false;
testSuite.IgnoreReason = attr.Reason;
}
Type fixtureAttribute = typeof(NUnit.Framework.TestFixtureAttribute);
attributes = fixture.GetType().GetCustomAttributes(fixtureAttribute, false);
if(attributes.Length == 1)
{
NUnit.Framework.TestFixtureAttribute fixtureAttr =
(NUnit.Framework.TestFixtureAttribute)attributes[0];
testSuite.Description = fixtureAttr.Description;
}
////////////////////////////////////////////////////////////////////////
// Uncomment the following code block to allow including Suites in the
// tree of tests. This causes a problem when the same test is added
// in multiple suites so we need to either fix it or prevent it.
//
// See also a line to change in TestSuiteBuilder.cs
////////////////////////////////////////////////////////////////////////
// PropertyInfo [] properties = fixture.GetType().GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly);
// foreach(PropertyInfo property in properties)
// {
// object[] attrributes = property.GetCustomAttributes(typeof(NUnit.Framework.SuiteAttribute),false);
// if(attrributes.Length>0)
// {
// MethodInfo method = property.GetGetMethod(true);
// if(method.ReturnType!=typeof(NUnit.Core.TestSuite) || method.GetParameters().Length>0)
// {
// testSuite.ShouldRun = false;
// testSuite.IgnoreReason = "Invalid suite property method signature";
// }
// else
// {
// TestSuite suite = (TestSuite)property.GetValue(null, new Object[0]);
// foreach( Test test in suite.Tests )
// testSuite.Add( test );
// }
// }
// }
MethodInfo [] methods = fixture.GetType().GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static|BindingFlags.NonPublic);
foreach(MethodInfo method in methods)
{
TestCase testCase = TestCaseBuilder.Make(fixture, method);
if(testCase != null)
{
testCase.AssemblyKey = testSuite.AssemblyKey;
testSuite.Add(testCase);
}
}
if(testSuite.CountTestCases == 0)
{
testSuite.ShouldRun = false;
testSuite.IgnoreReason = testSuite.Name + " does not have any tests";
}
}
private void CheckSuiteProperty(PropertyInfo property)
{
MethodInfo method = property.GetGetMethod(true);
if(method.ReturnType!=typeof(NUnit.Core.TestSuite))
throw new InvalidSuiteException("Invalid suite property method signature");
if(method.GetParameters().Length>0)
throw new InvalidSuiteException("Invalid suite property method signature");
}
public override ArrayList Tests
{
get { return tests; }
}
public override bool IsSuite
{
get { return true; }
}
public override bool IsTestCase
{
get { return false; }
}
///
/// True if this is a fixture. May populate the test's
/// children as a side effect.
/// TODO: An easier way to tell this?
///
public override bool IsFixture
{
get
{
// We have no way of constructing an empty suite unless it's a fixture
if ( Tests.Count == 0 ) return true;
// Any suite with children is a fixture if the children are test cases
ITest firstChild = (ITest)Tests[0];
return !firstChild.IsSuite;
}
}
public override int CountTestCases
{
get
{
int count = 0;
foreach(Test test in Tests)
{
count += test.CountTestCases;
}
return count;
}
}
private bool suiteRunning = false;
public bool SuiteRunning
{
get { return suiteRunning; }
}
public override TestResult Run(EventListener listener)
{
suiteRunning = true;
TestSuiteResult suiteResult = new TestSuiteResult(this, Name);
listener.SuiteStarted(this);
suiteResult.Executed = true;
long startTime = DateTime.Now.Ticks;
doFixtureSetup(suiteResult);
RunAllTests(suiteResult,listener);
doFixtureTearDown(suiteResult);
long stopTime = DateTime.Now.Ticks;
double time = ((double)(stopTime - startTime)) / (double)TimeSpan.TicksPerSecond;
suiteResult.Time = time;
if(!ShouldRun) suiteResult.NotRun(this.IgnoreReason);
listener.SuiteFinished(suiteResult);
suiteRunning = false;
return suiteResult;
}
public void InvokeFixtureTearDown()
{
if (this.fixtureTearDown != null)
this.InvokeMethod(fixtureTearDown, fixture);
}
private void doFixtureTearDown(TestSuiteResult suiteResult)
{
if (this.ShouldRun)
{
try
{
InvokeFixtureTearDown();
}
catch (Exception ex)
{
handleFixtureException(suiteResult, ex);
}
}
if (this.IgnoreReason == FIXTURE_SETUP_FAILED)
{
this.ShouldRun = true;
this.IgnoreReason = null;
}
}
private void doFixtureSetup(TestSuiteResult suiteResult)
{
try
{
InvoikeFixtureSetUp();
}
catch (Exception ex)
{
handleFixtureException(suiteResult, ex);
this.ShouldRun = false;
this.IgnoreReason = FIXTURE_SETUP_FAILED;
}
}
public void InvoikeFixtureSetUp()
{
if (this.fixtureSetUp != null)
this.InvokeMethod(fixtureSetUp, fixture);
}
private void handleFixtureException(TestSuiteResult result, Exception ex)
{
NunitException nex = ex as NunitException;
if (nex != null)
ex = nex.InnerException;
result.Executed = false;
result.NotRun(ex.ToString());
result.StackTrace = ex.StackTrace;
}
protected virtual void RunAllTests(TestSuiteResult suiteResult,EventListener listener)
{
foreach(Test test in ArrayList.Synchronized(Tests))
{
if (this.ShouldRun == false)
{
test.ShouldRun = false;
if (test.IgnoreReason == null)
test.IgnoreReason = FIXTURE_SETUP_FAILED;
}
suiteResult.AddResult(test.Run(listener));
if (this.ShouldRun == false)
{
if (test.IgnoreReason == FIXTURE_SETUP_FAILED)
{
test.ShouldRun = true;
test.IgnoreReason = null;
}
}
}
}
}
}