namespace NUnit.Framework {
using System;
using System.Collections;
using System.Reflection;
/// A TestSuite is a Composite of Tests.
/// It runs a collection of test cases. Here is an example using
/// the dynamic test definition.
///
/// TestSuite suite= new TestSuite();
/// suite.AddTest(new MathTest("TestAdd"));
/// suite.AddTest(new MathTest("TestDivideByZero"));
///
/// Alternatively, a TestSuite can extract the Tests to be run automatically.
/// To do so you pass the class of your TestCase class to the
/// TestSuite constructor.
///
/// TestSuite suite= new TestSuite(typeof(MathTest));
///
/// This constructor creates a suite with all the methods
/// starting with "Test" that take no arguments.
///
public class TestSuite: MarshalByRefObject, ITest {
private ArrayList fTests= new ArrayList(10);
private string fName;
private bool fHasWarnings = false;
/// Constructs an empty TestSuite.
public TestSuite() {
}
/// Constructs a TestSuite from the given class.
/// Adds all the methods
/// starting with "Test" as test cases to the suite.
/// Parts of this method was written at 2337 meters in the Hüffihütte,
/// Kanton Uri
public TestSuite(Type theClass) {
fName= theClass.Name;
ConstructorInfo constructor = GetConstructor(theClass);
if (constructor == null) {
AddTest(Warning("Class "+theClass.Name+" has no public constructor TestCase(String name)"));
return;
}
if (theClass.IsNotPublic) {
AddTest(Warning("Class "+theClass.Name+" is not public"));
return;
}
Type superClass= theClass;
ArrayList names= new ArrayList();
while (typeof(ITest).IsAssignableFrom(superClass)) {
MethodInfo[] methods= superClass.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
for (int i= 0; i < methods.Length; i++) {
AddTestMethod(methods[i], names, constructor);
}
superClass= superClass.BaseType;
}
if (fTests.Count == 0)
AddTest(Warning("No Tests found in "+theClass.ToString()));
}
///
///
///
///
///
public TestSuite(Type theClass, ref bool hasNonWarningTests) {
hasNonWarningTests = false;
fName= theClass.ToString();
ConstructorInfo constructor= GetConstructor(theClass);
if (constructor == null) {
return;
}
if (theClass.IsNotPublic) {
return;
}
Type superClass= theClass;
ArrayList names= new ArrayList();
while (typeof(ITest).IsAssignableFrom(superClass)) {
MethodInfo[] methods= superClass.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
for (int i= 0; i < methods.Length; i++) {
AddTestMethod(methods[i], names, constructor);
}
superClass= superClass.BaseType;
}
if (fHasWarnings) {
hasNonWarningTests = false;
} else {
hasNonWarningTests = (fTests.Count != 0);
}
}
/// Constructs an empty TestSuite.
public TestSuite(string name) {
fName= name;
}
/// Adds a test to the suite.
public void AddTest(ITest test) {
fTests.Add(test);
}
private void AddTestMethod(MethodInfo m, ArrayList names,
ConstructorInfo constructor) {
string name= m.Name;
if (names.Contains(name))
return;
if (IsPublicTestMethod(m)) {
names.Add(name);
Object[] args= new Object[]{name};
try {
AddTest((ITest)constructor.Invoke(args));
} catch (TypeLoadException e) {
AddTest(Warning("Cannot instantiate test case: "+name + "( " + e.ToString() + ")"));
} catch (TargetInvocationException e) {
AddTest(Warning("Exception in constructor: "+name + "( " + e.ToString() + ")"));
}
catch (MemberAccessException e)
{
AddTest(Warning("Cannot access test case: "+name + "( " + e.ToString() + ")"));
}
} else { // almost a test method
if (IsTestMethod(m))
AddTest(Warning("test method isn't public: "+m.Name));
}
}
/// Adds the tests from the given class to the suite
public void AddTestSuite(Type testClass) {
AddTest(new TestSuite(testClass));
}
/// The number of test cases that will be run by this test.
public int CountTestCases {
get {
int count= 0;
foreach (ITest test in Tests) {
count += test.CountTestCases;
}
return count;
}
}
/// Gets a constructor which takes a single string as
/// its argument.
private ConstructorInfo GetConstructor(Type theClass) {
Type[] args= { typeof(string) };
return theClass.GetConstructor(args);
}
///
/// Returns the name of the suite. Not all test suites have a name
/// and this method can return null.
///
public string Name {
get { return fName; }
}
private bool IsPublicTestMethod(MethodInfo m) {
return IsTestMethod(m) && m.IsPublic;
}
private bool IsTestMethod(MethodInfo m) {
string name= m.Name;
ParameterInfo[] parameters= m.GetParameters();
Type returnType= m.ReturnType;
return parameters.Length == 0 && name.ToLower().StartsWith("test")
&& returnType.Equals(typeof(void));
}
/// Runs the Tests and collects their result in a
/// TestResult.
public virtual void Run(TestResult result) {
foreach (ITest test in Tests) {
if (result.ShouldStop )
break;
RunTest(test, result);
}
}
///
///
///
///
///
public virtual void RunTest(ITest test, TestResult result) {
test.Run(result);
}
/// The test at the given index.
/// Formerly TestAt(int).
public ITest this[int index] {
get {return (ITest)fTests[index]; }
}
/// The number of Tests in this suite.
public int TestCount {
get {return fTests.Count; }
}
/// The Tests as an ArrayList.
public ArrayList Tests {
get { return fTests; }
}
///
///
///
///
public override string ToString() {
if (Name != null)
return Name;
return base.ToString();
}
private ITest Warning(string message) {
fHasWarnings = true;
return new WarningFail(message);
}
/// Returns a test which will fail and log a warning
/// message.
public class WarningFail: TestCase {
private string fMessage;
///
///
///
///
public WarningFail(string message): base("warning") {
fMessage = message;
}
///
///
///
protected override void RunTest() {
Fail(fMessage);
}
}
}
}