Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using System.Collections.Specialized;
namespace NUnit.Core
{
/// <summary>
/// TestCaseDecorator is used to add functionality to
/// another TestCase, which it aggregates.
/// </summary>
public abstract class AbstractTestCaseDecoration : TestCase
{
protected TestCase testCase;
public AbstractTestCaseDecoration( TestCase testCase )
: base( (TestName)testCase.TestName.Clone() )
{
this.testCase = testCase;
this.RunState = testCase.RunState;
this.IgnoreReason = testCase.IgnoreReason;
this.Description = testCase.Description;
this.Categories = new System.Collections.ArrayList(testCase.Categories);
if (testCase.Properties != null)
{
this.Properties = new ListDictionary();
foreach (DictionaryEntry entry in testCase.Properties)
this.Properties.Add(entry.Key, entry.Value);
}
}
public override int TestCount
{
get { return testCase.TestCount; }
}
}
}

View File

@@ -0,0 +1,13 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Reflection;
[assembly: CLSCompliant(true)]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("../../nunit.snk")]
[assembly: AssemblyKeyName("")]

View File

@@ -0,0 +1,168 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Reflection;
using System.Text;
using System.IO;
namespace NUnit.Core
{
/// <summary>
/// AssemblyReader knows how to find various things in an assembly header
/// </summary>
public class AssemblyReader : IDisposable
{
private string assemblyPath;
private BinaryReader rdr;
private FileStream fs;
UInt16 dos_magic = 0xffff;
uint pe_signature = 0xffffffff;
UInt16 numDataSections;
UInt16 optionalHeaderSize;
private uint peHeader = 0;
private uint fileHeader = 0;
private uint optionalHeader = 0;
private uint dataDirectory = 0;
private uint dataSections = 0;
private struct Section
{
public uint virtualAddress;
public uint virtualSize;
public uint fileOffset;
};
private Section[] sections;
public AssemblyReader( string assemblyPath )
{
this.assemblyPath = assemblyPath;
CalcHeaderOffsets();
}
public AssemblyReader( Assembly assembly )
{
this.assemblyPath = TestFixtureBuilder.GetAssemblyPath( assembly );
CalcHeaderOffsets();
}
private void CalcHeaderOffsets()
{
this.fs = new FileStream( assemblyPath, FileMode.Open, FileAccess.Read );
this.rdr = new BinaryReader( fs );
dos_magic = rdr.ReadUInt16();
if ( dos_magic == 0x5a4d )
{
fs.Position = 0x3c;
peHeader = rdr.ReadUInt32();
fileHeader = peHeader + 4;
optionalHeader = fileHeader + 20;
dataDirectory = optionalHeader + 96;
// dotNetDirectoryEntry = dataDirectory + 14 * 8;
fs.Position = peHeader;
pe_signature = rdr.ReadUInt32();
rdr.ReadUInt16(); // machine
numDataSections = rdr.ReadUInt16();
fs.Position += 12;
optionalHeaderSize = rdr.ReadUInt16();
dataSections = optionalHeader + optionalHeaderSize;
sections = new Section[numDataSections];
fs.Position = dataSections;
for( int i = 0; i < numDataSections; i++ )
{
fs.Position += 8;
sections[i].virtualSize = rdr.ReadUInt32();
sections[i].virtualAddress = rdr.ReadUInt32();
uint rawDataSize = rdr.ReadUInt32();
sections[i].fileOffset = rdr.ReadUInt32();
if ( sections[i].virtualSize == 0 )
sections[i].virtualSize = rawDataSize;
fs.Position += 16;
}
}
}
private uint DataDirectoryRva( int n )
{
fs.Position = dataDirectory + n * 8;
return rdr.ReadUInt32();
}
private uint RvaToLfa( uint rva )
{
for( int i = 0; i < numDataSections; i++ )
if ( rva >= sections[i].virtualAddress && rva < sections[i].virtualAddress + sections[i].virtualSize )
return rva - sections[i].virtualAddress + sections[i].fileOffset;
return 0;
}
public string AssemblyPath
{
get { return assemblyPath; }
}
public bool IsValidPeFile
{
get { return dos_magic == 0x5a4d && pe_signature == 0x00004550; }
}
public bool IsDotNetFile
{
get { return IsValidPeFile && DataDirectoryRva(14) != 0; }
}
public string ImageRuntimeVersion
{
get
{
string runtimeVersion = string.Empty;
uint rva = DataDirectoryRva(14);
if ( rva != 0 )
{
fs.Position = RvaToLfa( rva ) + 8;
uint metadata = rdr.ReadUInt32();
fs.Position = RvaToLfa( metadata );
if ( rdr.ReadUInt32() == 0x424a5342 )
{
// Copy string representing runtime version
fs.Position += 12;
StringBuilder sb = new StringBuilder();
char c;
while ((c = rdr.ReadChar())!= '\0')
sb.Append(c);
if (sb[0] == 'v') // Last sanity check
runtimeVersion = sb.ToString();
// Could do fixups here for bad values in older files
// like 1.x86, 1.build, etc. But we are only using
// the major version anyway
}
}
return runtimeVersion;
}
}
public void Dispose()
{
if ( fs != null )
fs.Close();
if ( rdr != null )
rdr.Close();
fs = null;
rdr = null;
}
}
}

View File

@@ -0,0 +1,122 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
namespace NUnit.Core
{
using System;
using System.IO;
using System.Reflection;
using System.Collections;
/// <summary>
/// Class adapted from NUnitAddin for use in handling assemblies that are not
/// found in the test AppDomain.
/// </summary>
public class AssemblyResolver : MarshalByRefObject, IDisposable
{
private class AssemblyCache
{
private Hashtable _resolved = new Hashtable();
public bool Contains( string name )
{
return _resolved.ContainsKey( name );
}
public Assembly Resolve( string name )
{
if ( _resolved.ContainsKey( name ) )
return (Assembly)_resolved[name];
return null;
}
public void Add( string name, Assembly assembly )
{
_resolved[name] = assembly;
}
}
private AssemblyCache _cache = new AssemblyCache();
private ArrayList _dirs = new ArrayList();
public AssemblyResolver()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public void Dispose()
{
AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public void AddFile( string file )
{
Assembly assembly = Assembly.LoadFrom( file );
_cache.Add(assembly.GetName().FullName, assembly);
}
public void AddFiles( string directory, string pattern )
{
if ( Directory.Exists( directory ) )
foreach( string file in Directory.GetFiles( directory, pattern ) )
AddFile( file );
}
public void AddDirectory( string directory )
{
if ( Directory.Exists( directory ) )
_dirs.Add( directory );
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string fullName = args.Name;
int index = fullName.IndexOf(',');
if(index == -1) // Only resolve using full name.
{
NTrace.Debug( string.Format("Not a strong name: {0}", fullName ),
"'AssemblyResolver'" );
return null;
}
if ( _cache.Contains( fullName ) )
{
NTrace.Info( string.Format( "Resolved from Cache: {0}", fullName ),
"'AssemblyResolver'" );
return _cache.Resolve(fullName);
}
foreach( string dir in _dirs )
{
foreach( string file in Directory.GetFiles( dir, "*.dll" ) )
{
string fullFile = Path.Combine( dir, file );
try
{
if ( AssemblyName.GetAssemblyName( fullFile ).FullName == fullName )
{
NTrace.Info( string.Format( "Added to Cache: {0}", fullFile ),
"'AssemblyResolver'" );
AddFile( fullFile );
return _cache.Resolve( fullName );
}
}
catch
{
// Keep going if there's a bad assembly
NTrace.Debug( string.Format( "Bad assembly: {0}", fullFile ), "AssemblyResolver");
}
}
}
NTrace.Debug( string.Format( "Not in Cache: {0}", fullName),
"'AssemblyResolver'");
return null;
}
}
}

View File

@@ -0,0 +1,201 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Collections;
using System.Reflection;
namespace NUnit.Core.Builders
{
/// <summary>
/// AbstractFixtureBuilder may serve as a base class for
/// implementing a suite builder. It provides a templated
/// implementation of the BuildFrom method as well as a
/// number of useful methods that derived classes may use.
/// </summary>
public abstract class AbstractFixtureBuilder : Extensibility.ISuiteBuilder
{
#region Instance Fields
/// <summary>
/// The TestSuite being constructed;
/// </summary>
protected TestSuite suite;
/// <summary>
/// The fixture builder's own test case builder collection
/// </summary>
protected Extensibility.TestCaseBuilderCollection testCaseBuilders =
new Extensibility.TestCaseBuilderCollection(CoreExtensions.Host);
#endregion
#region Abstract Methods
/// <summary>
/// Examine the type and determine if it is suitable for
/// this builder to use in building a TestSuite.
///
/// Note that returning false will cause the type to be ignored
/// in loading the tests. If it is desired to load the suite
/// but label it as non-runnable, ignored, etc., then this
/// method must return true.
/// </summary>
/// <param name="type">The type of the fixture to be used</param>
/// <returns>True if the type can be used to build a TestSuite</returns>
public abstract bool CanBuildFrom(Type type);
/// <summary>
/// Method that actually creates a new TestSuite object
///
/// Derived classes must override this method.
/// </summary>
/// <param name="type">The user fixture type</param>
/// <returns></returns>
protected abstract TestSuite MakeSuite( Type type );
#endregion
#region Virtual Methods
/// <summary>
/// Templated implementaton of ISuiteBuilder.BuildFrom. Any
/// derived builder may choose to override this method in
/// it's entirety or to let it stand and override some of
/// the virtual methods that it calls.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public virtual Test BuildFrom(Type type)
{
this.suite = MakeSuite(type);
SetTestSuiteProperties(type, suite);
AddTestCases(type);
if ( this.suite.RunState != RunState.NotRunnable && this.suite.TestCount == 0)
{
this.suite.RunState = RunState.NotRunnable;
this.suite.IgnoreReason = suite.TestName.Name + " does not have any tests";
}
return this.suite;
}
/// <summary>
/// Method that sets properties of the test suite based on the
/// information in the provided Type.
///
/// Derived classes normally override this method and should
/// call the base method or include equivalent code.
/// </summary>
/// <param name="type">The type to examine</param>
/// <param name="suite">The test suite being constructed</param>
protected virtual void SetTestSuiteProperties( Type type, TestSuite suite )
{
string reason = null;
if (!IsValidFixtureType(type, ref reason) )
{
this.suite.RunState = RunState.NotRunnable;
this.suite.IgnoreReason = reason;
}
}
/// <summary>
/// Virtual method that returns true if the fixture type is valid
/// for use by the builder. If not, it returns false and sets
/// reason to an appropriate message. As implemented in this class,
/// the method checks that a default constructor is available. You
/// may override this method in a derived class in order to make
/// different or additional checks.
/// </summary>
/// <param name="fixtureType">The fixture type</param>
/// <param name="reason">The reason this fixture is not valid</param>
/// <returns>True if the fixture type is valid, false if not</returns>
protected virtual bool IsValidFixtureType( Type fixtureType, ref string reason )
{
if (fixtureType.IsAbstract)
{
reason = string.Format("{0} is an abstract class", fixtureType.FullName);
return false;
}
if (Reflect.GetConstructor(fixtureType) == null)
{
reason = string.Format( "{0} does not have a valid constructor", fixtureType.FullName );
return false;
}
return true;
}
/// <summary>
/// Method to add test cases to the newly constructed suite.
/// The default implementation looks at each candidate method
/// and tries to build a test case from it. It will only need
/// to be overridden if some other approach, such as reading a
/// datafile is used to generate test cases.
/// </summary>
/// <param name="fixtureType"></param>
protected virtual void AddTestCases( Type fixtureType )
{
IList methods = GetCandidateTestMethods( fixtureType );
foreach(MethodInfo method in methods)
{
Test test = BuildTestCase(method);
if(test != null)
{
this.suite.Add( test );
}
}
}
/// <summary>
/// Method to create a test case from a MethodInfo and add
/// it to the suite being built. It first checks to see if
/// any global TestCaseBuilder addin wants to build the
/// test case. If not, it uses the internal builder
/// collection maintained by this fixture builder. After
/// building the test case, it applies any decorators
/// that have been installed.
///
/// The default implementation has no test case builders.
/// Derived classes should add builders to the collection
/// in their constructor.
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
protected virtual Test BuildTestCase( MethodInfo method )
{
// TODO: Review order of using builders
Test test = CoreExtensions.Host.TestBuilders.BuildFrom( method );
if ( test == null && this.testCaseBuilders.CanBuildFrom( method ) )
test = this.testCaseBuilders.BuildFrom( method );
if ( test != null )
test = CoreExtensions.Host.TestDecorators.Decorate( test, method );
return test;
}
/// <summary>
/// Method to return all methods in a fixture that should be examined
/// to see if they are test methods. The default returns all methods
/// of the fixture: public and private, instance and static, declared
/// and inherited.
///
/// While this method may be overridden, it should normally not be.
/// If it is overridden to eliminate certain methods, they will be
/// silently ignored. Generally, it is better to include them in the
/// list and let the TestCaseBuilders decide how to handle them.
/// </summary>
/// <param name="fixtureType"></param>
/// <returns></returns>
protected IList GetCandidateTestMethods( Type fixtureType )
{
return fixtureType.GetMethods( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static );
}
#endregion
}
}

View File

@@ -0,0 +1,105 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System.Reflection;
namespace NUnit.Core.Builders
{
/// <summary>
/// AbstractTestCaseBuilder may serve as a base class for
/// implementing a test case builder. It provides a templated
/// implementation of the BuildFrom method.
///
/// Developers of extended test cases may choose to inherit
/// from this class, although NUnitTestCaseBuilder will
/// probably be more useful if the extension is intended
/// to work like an NUnit test case.
/// </summary>
public abstract class AbstractTestCaseBuilder : Extensibility.ITestCaseBuilder
{
#region Instance Fields
protected int runnerID;
protected TestCase testCase;
#endregion
#region Abstract Methods
/// <summary>
/// Examine the method and determine if it is suitable for
/// this builder to use in building a TestCase.
///
/// Note that returning false will cause the method to be ignored
/// in loading the tests. If it is desired to load the method
/// but label it as non-runnable, ignored, etc., then this
/// method must return true.
///
/// Derived classes must override this method.
/// </summary>
/// <param name="method">The test method to examine</param>
/// <returns>True is the builder can use this method</returns>
public abstract bool CanBuildFrom(System.Reflection.MethodInfo method);
/// <summary>
/// Method that actually creates a new test case object.
///
/// Derived classes must override this method.
/// </summary>
/// <param name="method">The test method to examine</param>
/// <returns>An object derived from TestCase</returns>
protected abstract TestCase MakeTestCase( MethodInfo method );
/// <summary>
/// Method that sets properties of the test case based on the
/// information in the provided MethodInfo.
///
/// Derived classes must override this method.
/// </summary>
/// <param name="method">The test method to examine</param>
/// <param name="testCase">The test case being constructed</param>
protected abstract void SetTestProperties( MethodInfo method, TestCase testCase );
#endregion
#region Virtual Methods
/// <summary>
/// Templated implementaton of ITestCaseBuilder.BuildFrom.
///
/// Any derived builder may choose to override this method in
/// it's entirety or to let it stand and override some of
/// the virtual methods that it calls.
/// </summary>
/// <param name="method">The method for which a test case is to be built</param>
/// <returns>A TestCase or null</returns>
public virtual Test BuildFrom(System.Reflection.MethodInfo method)
{
if ( !HasValidTestCaseSignature( method ) )
return new NotRunnableTestCase( method );
TestCase testCase = MakeTestCase( method );
if ( testCase != null )
SetTestProperties( method , testCase );
return testCase;
}
/// <summary>
/// Virtual method that checks the signature of a potential test case to
/// determine if it is valid. The default implementation requires methods
/// to be public, non-abstract instance methods, taking no parameters and
/// returning void. Methods not meeting these criteria will be marked by
/// NUnit as non-runnable.
/// </summary>
/// <param name="method">The method to be checked</param>
/// <returns>True if the method signature is valid, false if not</returns>
protected virtual bool HasValidTestCaseSignature( MethodInfo method )
{
return !method.IsStatic
&& !method.IsAbstract
&& method.IsPublic
&& method.GetParameters().Length == 0
&& method.ReturnType.Equals(typeof(void) );
}
#endregion
}
}

View File

@@ -0,0 +1,26 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
namespace NUnit.Core.Builders
{
/// <summary>
/// Built-in SuiteBuilder for LegacySuite
/// </summary>
public class LegacySuiteBuilder : Extensibility.ISuiteBuilder
{
public bool CanBuildFrom( Type type )
{
return LegacySuite.GetSuiteProperty( type ) != null;
}
public Test BuildFrom( Type type )
{
return new LegacySuite( type );
}
}
}

View File

@@ -0,0 +1,76 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Configuration;
using System.Diagnostics;
namespace NUnit.Core.Builders
{
public class NUnitTestCaseBuilder : AbstractTestCaseBuilder
{
private bool allowOldStyleTests = NUnitFramework.AllowOldStyleTests;
#region AbstractTestCaseBuilder Overrides
/// <summary>
/// Determine if the method is an NUnit test method.
/// The method must normally be marked with the test
/// attribute for this to be true. If the test config
/// file sets AllowOldStyleTests to true, then any
/// method beginning "test..." (case-insensitive)
/// is treated as a test unless it is also marked
/// as a setup or teardown method.
/// </summary>
/// <param name="method">A MethodInfo for the method being used as a test method</param>
/// <returns>True if the builder can create a test case from this method</returns>
public override bool CanBuildFrom(MethodInfo method)
{
if ( Reflect.HasAttribute( method, NUnitFramework.TestAttribute, false ) )
return true;
if (allowOldStyleTests)
{
Regex regex = new Regex("^(?i:test)");
if ( regex.Match(method.Name).Success
&& !NUnitFramework.IsSetUpMethod( method )
&& !NUnitFramework.IsTearDownMethod( method )
&& !NUnitFramework.IsFixtureSetUpMethod( method )
&& !NUnitFramework.IsFixtureTearDownMethod( method ) )
return true;
}
return false;
}
/// <summary>
/// Create an NUnitTestMethod
/// </summary>
/// <param name="method">A MethodInfo for the method being used as a test method</param>
/// <returns>A new NUnitTestMethod</returns>
protected override TestCase MakeTestCase(MethodInfo method)
{
return new NUnitTestMethod( method );
}
/// <summary>
/// Set additional properties of the newly created test case based
/// on its attributes. As implemented, the method sets the test's
/// RunState, Description, Categories and Properties.
/// </summary>
/// <param name="method">A MethodInfo for the method being used as a test method</param>
/// <param name="testCase">The test case being constructed</param>
protected override void SetTestProperties( MethodInfo method, TestCase testCase )
{
NUnitFramework.ApplyCommonAttributes( method, testCase );
NUnitFramework.ApplyExpectedExceptionAttribute( method, (TestMethod)testCase );
}
#endregion
}
}

View File

@@ -0,0 +1,129 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;
namespace NUnit.Core.Builders
{
/// <summary>
/// Built-in SuiteBuilder for NUnit TestFixture
/// </summary>
public class NUnitTestFixtureBuilder : AbstractFixtureBuilder
{
public NUnitTestFixtureBuilder()
{
this.testCaseBuilders.Install( new NUnitTestCaseBuilder() );
}
#region AbstractFixtureBuilder Overrides
/// <summary>
/// Makes an NUnitTestFixture instance
/// </summary>
/// <param name="type">The type to be used</param>
/// <returns>An NUnitTestFixture as a TestSuite</returns>
protected override TestSuite MakeSuite( Type type )
{
return new NUnitTestFixture( type );
}
/// <summary>
/// Method that sets properties of the test suite based on the
/// information in the provided Type.
/// </summary>
/// <param name="type">The type to examine</param>
/// <param name="suite">The test suite being constructed</param>
protected override void SetTestSuiteProperties( Type type, TestSuite suite )
{
base.SetTestSuiteProperties( type, suite );
NUnitFramework.ApplyCommonAttributes( type, suite );
}
/// <summary>
/// Checks to see if the fixture type has the test fixture
/// attribute type specified in the parameters. Override
/// to allow additional types - based on name, for example.
/// </summary>
/// <param name="type">The fixture type to check</param>
/// <returns>True if the fixture can be built, false if not</returns>
public override bool CanBuildFrom(Type type)
{
return Reflect.HasAttribute( type, NUnitFramework.TestFixtureAttribute, true );
}
/// <summary>
/// Check that the fixture is valid. In addition to the base class
/// check for a valid constructor, this method ensures that there
/// is no more than one of each setup or teardown method and that
/// their signatures are correct.
/// </summary>
/// <param name="fixtureType">The type of the fixture to check</param>
/// <param name="reason">A message indicating why the fixture is invalid</param>
/// <returns>True if the fixture is valid, false if not</returns>
protected override bool IsValidFixtureType(Type fixtureType, ref string reason)
{
if (!base.IsValidFixtureType(fixtureType, ref reason))
return false;
if (!fixtureType.IsPublic && !fixtureType.IsNestedPublic)
{
reason = "Fixture class is not public";
return false;
}
return CheckSetUpTearDownMethod(fixtureType, "SetUp", NUnitFramework.SetUpAttribute, ref reason)
&& CheckSetUpTearDownMethod(fixtureType, "TearDown", NUnitFramework.TearDownAttribute, ref reason)
&& CheckSetUpTearDownMethod(fixtureType, "TestFixtureSetUp", NUnitFramework.FixtureSetUpAttribute, ref reason)
&& CheckSetUpTearDownMethod(fixtureType, "TestFixtureTearDown", NUnitFramework.FixtureTearDownAttribute, ref reason);
}
/// <summary>
/// Internal helper to check a single setup or teardown method
/// </summary>
/// <param name="fixtureType">The type to be checked</param>
/// <param name="attributeName">The short name of the attribute to be checked</param>
/// <returns>True if the method is present no more than once and has a valid signature</returns>
private bool CheckSetUpTearDownMethod(Type fixtureType, string name, string attributeName, ref string reason)
{
int count = Reflect.CountMethodsWithAttribute(
fixtureType, attributeName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly,
true);
if (count == 0) return true;
if (count > 1)
{
reason = string.Format("More than one {0} method", name);
return false;
}
MethodInfo theMethod = Reflect.GetMethodWithAttribute(
fixtureType, attributeName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly,
true);
if (theMethod != null)
{
if (theMethod.IsStatic ||
theMethod.IsAbstract ||
!theMethod.IsPublic && !theMethod.IsFamily ||
theMethod.GetParameters().Length != 0 ||
!theMethod.ReturnType.Equals(typeof(void)))
{
reason = string.Format("Invalid {0} method signature", name);
return false;
}
}
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,35 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
namespace NUnit.Core.Builders
{
/// <summary>
/// SetUpFixtureBuilder knows how to build a SetUpFixture.
/// </summary>
public class SetUpFixtureBuilder : Extensibility.ISuiteBuilder
{
public SetUpFixtureBuilder()
{
//
// TODO: Add constructor logic here //
}
#region ISuiteBuilder Members
public Test BuildFrom(Type type)
{
return new SetUpFixture( type );
}
public bool CanBuildFrom(Type type)
{
return Reflect.HasAttribute( type, NUnitFramework.SetUpFixtureAttribute, false );
}
#endregion
}
}

View File

@@ -0,0 +1,213 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using NUnit.Core.Extensibility;
namespace NUnit.Core.Builders
{
/// <summary>
/// Class that builds a TestSuite from an assembly
/// </summary>
public class TestAssemblyBuilder
{
#region Instance Fields
/// <summary>
/// The loaded assembly
/// </summary>
Assembly assembly;
/// <summary>
/// Our LegacySuite builder, which is only used when a
/// fixture has been passed by name on the command line.
/// </summary>
ISuiteBuilder legacySuiteBuilder;
private TestAssemblyInfo assemblyInfo = null;
#endregion
#region Properties
public Assembly Assembly
{
get { return assembly; }
}
public TestAssemblyInfo AssemblyInfo
{
get
{
if ( assemblyInfo == null && assembly != null )
{
string path = TestFixtureBuilder.GetAssemblyPath( assembly );
AssemblyReader rdr = new AssemblyReader( path );
Version runtimeVersion = new Version( rdr.ImageRuntimeVersion.Substring( 1 ) );
IList frameworks = CoreExtensions.Host.TestFrameworks.GetReferencedFrameworks( assembly );
assemblyInfo = new TestAssemblyInfo( path, runtimeVersion, frameworks );
}
return assemblyInfo;
}
}
#endregion
#region Constructor
public TestAssemblyBuilder()
{
// TODO: Keeping this separate till we can make
//it work in all situations.
legacySuiteBuilder = new NUnit.Core.Builders.LegacySuiteBuilder();
}
#endregion
#region Build Methods
public Test Build( string assemblyName, string testName, bool autoSuites )
{
if ( testName == null || testName == string.Empty )
return Build( assemblyName, autoSuites );
this.assembly = Load( assemblyName );
if ( assembly == null ) return null;
// If provided test name is actually the name of
// a type, we handle it specially
Type testType = assembly.GetType(testName);
if( testType != null )
return Build( assemblyName, testType, autoSuites );
// Assume that testName is a namespace and get all fixtures in it
IList fixtures = GetFixtures( assembly, testName );
if ( fixtures.Count > 0 )
return BuildTestAssembly( assemblyName, fixtures, autoSuites );
return null;
}
public TestSuite Build( string assemblyName, bool autoSuites )
{
this.assembly = Load( assemblyName );
if ( this.assembly == null ) return null;
IList fixtures = GetFixtures( assembly, null );
return BuildTestAssembly( assemblyName, fixtures, autoSuites );
}
private Test Build( string assemblyName, Type testType, bool autoSuites )
{
// TODO: This is the only situation in which we currently
// recognize and load legacy suites. We need to determine
// whether to allow them in more places.
if ( legacySuiteBuilder.CanBuildFrom( testType ) )
return legacySuiteBuilder.BuildFrom( testType );
else if ( TestFixtureBuilder.CanBuildFrom( testType ) )
return BuildTestAssembly( assemblyName,
new Test[] { TestFixtureBuilder.BuildFrom( testType ) }, autoSuites );
return null;
}
private TestSuite BuildTestAssembly( string assemblyName, IList fixtures, bool autoSuites )
{
TestSuite testAssembly = new TestSuite( assemblyName );
if ( autoSuites )
{
NamespaceTreeBuilder treeBuilder =
new NamespaceTreeBuilder( testAssembly );
treeBuilder.Add( fixtures );
testAssembly = treeBuilder.RootSuite;
}
else
foreach( TestSuite fixture in fixtures )
{
if ( fixture is SetUpFixture )
{
fixture.RunState = RunState.NotRunnable;
fixture.IgnoreReason = "SetUpFixture cannot be used when loading tests as a flat list of fixtures";
}
testAssembly.Add( fixture );
}
if ( fixtures.Count == 0 )
{
testAssembly.RunState = RunState.NotRunnable;
testAssembly.IgnoreReason = "Has no TestFixtures";
}
NUnitFramework.ApplyCommonAttributes( assembly, testAssembly );
// TODO: Make this an option? Add Option to sort assemblies as well?
testAssembly.Sort();
return testAssembly;
}
#endregion
#region Helper Methods
private Assembly Load(string path)
{
Assembly assembly = null;
// Change currentDirectory in case assembly references unmanaged dlls
using( new DirectorySwapper( Path.GetDirectoryName( path ) ) )
{
// Throws if this isn't a managed assembly or if it was built
// with a later version of the same assembly.
AssemblyName.GetAssemblyName( Path.GetFileName( path ) );
// TODO: Figure out why we can't load using the assembly name
// in all cases. Might be a problem with the tests themselves.
assembly = Assembly.Load(Path.GetFileNameWithoutExtension(path));
if ( assembly != null )
CoreExtensions.Host.InstallAdhocExtensions( assembly );
NTrace.Info( "Loaded assembly " + assembly.FullName, "'TestAssemblyBuilder'" );
return assembly;
}
}
private IList GetFixtures( Assembly assembly, string ns )
{
ArrayList fixtures = new ArrayList();
IList testTypes = GetCandidateFixtureTypes( assembly, ns );
foreach(Type testType in testTypes)
{
if( TestFixtureBuilder.CanBuildFrom( testType ) )
fixtures.Add( TestFixtureBuilder.BuildFrom( testType ) );
}
return fixtures;
}
private IList GetCandidateFixtureTypes( Assembly assembly, string ns )
{
IList types = assembly.GetTypes();
if ( ns == null || ns == string.Empty || types.Count == 0 )
return types;
string prefix = ns + "." ;
ArrayList result = new ArrayList();
foreach( Type type in types )
if ( type.FullName.StartsWith( prefix ) )
result.Add( type );
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,215 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using NUnit.Core.Extensibility;
namespace NUnit.Core
{
/// <summary>
/// CoreExtensions is a singleton class that groups together all
/// the extension points that are supported in the test domain.
/// It also provides access to the test builders and decorators
/// by other parts of the NUnit core.
/// </summary>
public class CoreExtensions : ExtensionHost, IService
{
#region Instance Fields
private IAddinRegistry addinRegistry;
private bool initialized;
private SuiteBuilderCollection suiteBuilders;
private TestCaseBuilderCollection testBuilders;
private TestDecoratorCollection testDecorators;
private EventListenerCollection listeners;
// private log4net.Appender.ConsoleAppender appender;
#endregion
#region CoreExtensions Singleton
private static CoreExtensions host;
public static CoreExtensions Host
{
get
{
if (host == null)
host = new CoreExtensions();
return host;
}
}
#endregion
#region Constructors
public CoreExtensions()
{
this.suiteBuilders = new SuiteBuilderCollection(this);
this.testBuilders = new TestCaseBuilderCollection(this);
this.testDecorators = new TestDecoratorCollection(this);
this.listeners = new EventListenerCollection(this);
this.extensions = new IExtensionPoint[]
{ suiteBuilders, testBuilders, testDecorators, listeners };
this.supportedTypes = ExtensionType.Core;
// TODO: This should be somewhere central
// string logfile = Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData );
// logfile = Path.Combine( logfile, "NUnit" );
// logfile = Path.Combine( logfile, "NUnitTest.log" );
//
// appender = new log4net.Appender.ConsoleAppender();
//// appender.File = logfile;
//// appender.AppendToFile = true;
//// appender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
// appender.Layout = new log4net.Layout.PatternLayout(
// "%date{ABSOLUTE} %-5level [%4thread] %logger{1}: PID=%property{PID} %message%newline" );
// appender.Threshold = log4net.Core.Level.All;
// log4net.Config.BasicConfigurator.Configure(appender);
}
#endregion
#region Properties
public bool Initialized
{
get { return initialized; }
}
/// <summary>
/// Our AddinRegistry may be set from outside or passed into the domain
/// </summary>
public IAddinRegistry AddinRegistry
{
get
{
if ( addinRegistry == null )
addinRegistry = AppDomain.CurrentDomain.GetData( "AddinRegistry" ) as IAddinRegistry;
return addinRegistry;
}
set { addinRegistry = value; }
}
public ISuiteBuilder SuiteBuilders
{
get { return suiteBuilders; }
}
public ITestCaseBuilder TestBuilders
{
get { return testBuilders; }
}
public ITestDecorator TestDecorators
{
get { return testDecorators; }
}
public EventListener Listeners
{
get { return listeners; }
}
public FrameworkRegistry TestFrameworks
{
get { return frameworks; }
}
#endregion
#region Public Methods
public void InstallBuiltins()
{
NTrace.Info( "Installing Builtins" );
// Define NUnit Framework
FrameworkRegistry.Register( "NUnit", "nunit.framework" );
// Install builtin SuiteBuilders - Note that the
// NUnitTestCaseBuilder is installed whenever
// an NUnitTestFixture is being populated and
// removed afterward.
suiteBuilders.Install( new Builders.NUnitTestFixtureBuilder() );
suiteBuilders.Install( new Builders.SetUpFixtureBuilder() );
}
public void InstallAddins()
{
NTrace.Info( "Installing Addins" );
if( AddinRegistry != null )
{
foreach (Addin addin in AddinRegistry.Addins)
{
if ( (this.ExtensionTypes & addin.ExtensionType) != 0 )
{
try
{
Type type = Type.GetType(addin.TypeName);
if ( type == null )
{
AddinRegistry.SetStatus( addin.Name, AddinStatus.Error, "Could not locate type" );
NTrace.Error( "Failed to load " + addin.Name + " - Could not locate type" );
}
else if ( !InstallAddin( type ) )
{
AddinRegistry.SetStatus( addin.Name, AddinStatus.Error, "Install returned false" );
NTrace.Error( "Failed to load " +addin.Name + " - Install returned false" );
}
else
AddinRegistry.SetStatus( addin.Name, AddinStatus.Loaded, null );
}
catch( Exception ex )
{
AddinRegistry.SetStatus( addin.Name, AddinStatus.Error, ex.Message );
NTrace.Error( "Exception loading " + addin.Name + " - " + ex.Message );
}
}
}
}
}
public void InstallAdhocExtensions( Assembly assembly )
{
foreach ( Type type in assembly.GetExportedTypes() )
{
if ( type.GetCustomAttributes(typeof(NUnitAddinAttribute), false).Length == 1 )
InstallAddin( type );
}
}
#endregion
#region Helper Methods
private bool InstallAddin( Type type )
{
ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
object obj = ctor.Invoke( new object[0] );
IAddin theAddin = (IAddin)obj;
return theAddin.Install(this);
}
#endregion
#region IService Members
public void UnloadService()
{
// TODO: Add CoreExtensions.UnloadService implementation
}
public void InitializeService()
{
InstallBuiltins();
InstallAddins();
initialized = true;
}
#endregion
}
}

View File

@@ -0,0 +1,127 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Reflection;
using System.Globalization;
namespace NUnit.Core
{
public class CultureDetector
{
private CultureInfo currentCulture;
// Set whenever we fail to support a list of platforms
private string reason = string.Empty;
/// <summary>
/// Default constructor uses the current culutre.
/// </summary>
public CultureDetector()
{
this.currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
}
/// <summary>
/// Contruct a CultureHelper for a particular culture for testing.
/// </summary>
/// <param name="culture">The culture to be used</param>
public CultureDetector( string culture )
{
this.currentCulture = new CultureInfo( culture );
}
/// <summary>
/// Test to determine if one of a collection of culturess
/// is being used currently.
/// </summary>
/// <param name="cultures"></param>
/// <returns></returns>
public bool IsCultureSupported( string[] cultures )
{
foreach( string culture in cultures )
if ( IsCultureSupported( culture ) )
return true;
return false;
}
/// <summary>
/// Tests to determine if the current culture is supported
/// based on a culture attribute.
/// </summary>
/// <param name="platformAttribute">The attribute to examine</param>
/// <returns></returns>
public bool IsCultureSupported( Attribute cultureAttribute )
{
//Use reflection to avoid dependency on a particular framework version
string include = (string)Reflect.GetPropertyValue(
cultureAttribute, "Include",
BindingFlags.Public | BindingFlags.Instance );
string exclude = (string)Reflect.GetPropertyValue(
cultureAttribute, "Exclude",
BindingFlags.Public | BindingFlags.Instance );
try
{
if (include != null && !IsCultureSupported(include))
{
reason = string.Format("Only supported under culture {0}", include);
return false;
}
if (exclude != null && IsCultureSupported(exclude))
{
reason = string.Format("Not supported under culture {0}", exclude);
return false;
}
}
catch( ArgumentException ex )
{
reason = string.Format( "Invalid culture: {0}", ex.ParamName );
return false;
}
return true;
}
/// <summary>
/// Test to determine if the a particular culture or comma-
/// delimited set of cultures is in use.
/// </summary>
/// <param name="platform">Name of the culture or comma-separated list of culture names</param>
/// <returns>True if the culture is in use on the system</returns>
public bool IsCultureSupported( string culture )
{
culture = culture.Trim();
if ( culture.IndexOf( ',' ) >= 0 )
{
if ( IsCultureSupported( culture.Split( new char[] { ',' } ) ) )
return true;
}
else
{
if( this.currentCulture.Name == culture || this.currentCulture.TwoLetterISOLanguageName == culture)
return true;
}
this.reason = "Only supported under culture " + culture;
return false;
}
/// <summary>
/// Return the last failure reason. Results are not
/// defined if called before IsSupported( Attribute )
/// is called.
/// </summary>
public string Reason
{
get { return reason; }
}
}
}

View File

@@ -0,0 +1,174 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
namespace NUnit.Core
{
using System;
using System.Collections;
using System.IO;
/// <summary>
/// DelegatingTestRUnner is the abstract base for core TestRunner
/// implementations that operate by controlling a downstream
/// TestRunner. All calls are simply passed on to the
/// TestRunner that is provided to the constructor.
///
/// Although the class is abstract, it has no abstract
/// methods specified because each implementation will
/// need to override different methods. All methods are
/// specified using interface syntax and the derived class
/// must explicitly implement TestRunner in order to
/// redefine the selected methods.
/// </summary>
public abstract class DelegatingTestRunner : MarshalByRefObject, TestRunner
{
#region Instance Variables
/// <summary>
/// Our runner ID
/// </summary>
protected int runnerID;
/// <summary>
/// The downstream TestRunner
/// </summary>
private TestRunner testRunner;
/// <summary>
/// The event listener for the currently running test
/// </summary>
protected EventListener listener;
#endregion
#region Construction
public DelegatingTestRunner(TestRunner testRunner)
{
this.testRunner = testRunner;
this.runnerID = testRunner.ID;
}
/// <summary>
/// Protected constructor for runners that delay creation
/// of their downstream runner.
/// </summary>
protected DelegatingTestRunner( int runnerID )
{
this.runnerID = runnerID;
}
#endregion
#region Properties
public virtual int ID
{
get { return runnerID; }
}
public virtual bool Running
{
get { return testRunner != null && testRunner.Running; }
}
public virtual IList AssemblyInfo
{
get { return testRunner == null ? null : testRunner.AssemblyInfo; }
}
public virtual ITest Test
{
get { return testRunner == null ? null : testRunner.Test; }
}
public virtual TestResult TestResult
{
get { return testRunner == null ? null : testRunner.TestResult; }
}
/// <summary>
/// Protected property copies any settings to the downstream test runner
/// when it is set. Derived runners overriding this should call the base
/// or copy the settings themselves.
/// </summary>
protected virtual TestRunner TestRunner
{
get { return testRunner; }
set { testRunner = value; }
}
#endregion
#region Load and Unload Methods
public virtual bool Load( TestPackage package )
{
return this.testRunner.Load( package );
}
public virtual void Unload()
{
if ( this.testRunner != null )
this.testRunner.Unload();
}
#endregion
#region CountTestCases
public virtual int CountTestCases( ITestFilter filter )
{
return this.testRunner.CountTestCases( filter );
}
#endregion
#region Methods for Running Tests
public virtual TestResult Run(EventListener listener)
{
// Save active listener for derived classes
this.listener = listener;
return this.testRunner.Run(listener);
}
public virtual TestResult Run(EventListener listener, ITestFilter filter)
{
// Save active listener for derived classes
this.listener = listener;
return this.testRunner.Run(listener, filter);
}
public virtual void BeginRun( EventListener listener )
{
// Save active listener for derived classes
this.listener = listener;
this.testRunner.BeginRun( listener );
}
public virtual void BeginRun( EventListener listener, ITestFilter filter )
{
// Save active listener for derived classes
this.listener = listener;
this.testRunner.BeginRun( listener, filter );
}
public virtual TestResult EndRun()
{
return this.testRunner.EndRun();
}
public virtual void CancelRun()
{
this.testRunner.CancelRun();
}
public virtual void Wait()
{
this.testRunner.Wait();
}
#endregion
#region InitializeLifetimeService Override
public override object InitializeLifetimeService()
{
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,44 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
namespace NUnit.Core
{
/// <summary>
/// Utility class that allows changing the current directory
/// for the duration of some lexical scope and guaranteeing
/// that it will be restored upon exit.
///
/// Use it as follows:
/// using( new DirectorySwapper( @"X:\New\Path" )
/// {
/// // Code that operates in the new current directory
/// }
///
/// Instantiating DirectorySwapper without a path merely
/// saves the current directory, but does not change it.
/// </summary>
public class DirectorySwapper : IDisposable
{
private string savedDirectoryName;
public DirectorySwapper() : this( null ) { }
public DirectorySwapper( string directoryName )
{
savedDirectoryName = Environment.CurrentDirectory;
if ( directoryName != null && directoryName != string.Empty )
Environment.CurrentDirectory = directoryName;
}
public void Dispose()
{
Environment.CurrentDirectory = savedDirectoryName;
}
}
}

View File

@@ -0,0 +1,114 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
namespace NUnit.Core
{
using System;
using System.IO;
using System.Text;
public class EventListenerTextWriter : TextWriter
{
private EventListener eventListener;
private TestOutputType type;
public EventListenerTextWriter( EventListener eventListener, TestOutputType type )
{
this.eventListener = eventListener;
this.type = type;
}
override public void Write(char aChar)
{
this.eventListener.TestOutput( new TestOutput( aChar.ToString(), this.type ) );
}
override public void Write(string aString)
{
this.eventListener.TestOutput( new TestOutput( aString, this.type ) );
}
override public void WriteLine(string aString)
{
this.eventListener.TestOutput( new TestOutput( aString + this.NewLine, this.type ) );
}
override public System.Text.Encoding Encoding
{
get { return Encoding.Default; }
}
}
/// <summary>
/// This wrapper adds buffering to improve cross-domain performance.
/// </summary>
public class BufferedEventListenerTextWriter : TextWriter
{
private EventListener eventListener;
private TestOutputType type;
private const int MAX_BUFFER = 1024;
private StringBuilder sb = new StringBuilder( MAX_BUFFER );
public BufferedEventListenerTextWriter( EventListener eventListener, TestOutputType type )
{
this.eventListener = eventListener;
this.type = type;
}
public override Encoding Encoding
{
get
{
return Encoding.Default;
}
}
override public void Write(char ch)
{
lock( sb )
{
sb.Append( ch );
this.CheckBuffer();
}
}
override public void Write(string str)
{
lock( sb )
{
sb.Append( str );
this.CheckBuffer();
}
}
override public void WriteLine(string str)
{
lock( sb )
{
sb.Append( str );
sb.Append( base.NewLine );
this.CheckBuffer();
}
}
override public void Flush()
{
if ( sb.Length > 0 )
{
lock( sb )
{
TestOutput output = new TestOutput(sb.ToString(), this.type);
this.eventListener.TestOutput( output );
sb.Length = 0;
}
}
}
private void CheckBuffer()
{
if ( sb.Length >= MAX_BUFFER )
this.Flush();
}
}
}

View File

@@ -0,0 +1,169 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
namespace NUnit.Core
{
using System;
using System.Threading;
/// <summary>
/// EventPump pulls events out of an EventQueue and sends
/// them to a listener. It is used to send events back to
/// the client without using the CallContext of the test
/// runner thread.
/// </summary>
public class EventPump : IDisposable
{
#region Instance Variables
/// <summary>
/// The downstream listener to which we send events
/// </summary>
EventListener eventListener;
/// <summary>
/// The queue that holds our events
/// </summary>
EventQueue events;
/// <summary>
/// Thread to do the pumping
/// </summary>
Thread pumpThread;
/// <summary>
/// Indicator that we are pumping events
/// </summary>
private bool pumping;
/// <summary>
/// Indicator that we are stopping
/// </summary>
private bool stopping;
/// <summary>
/// If true, stop after sending RunFinished
/// </summary>
private bool autostop;
#endregion
#region Constructor
/// <summary>
/// Constructor
/// </summary>
/// <param name="eventListener">The EventListener to receive events</param>
/// <param name="events">The event queue to pull events from</param>
/// <param name="autostop">Set to true to stop pump after RunFinished</param>
public EventPump( EventListener eventListener, EventQueue events, bool autostop)
{
this.eventListener = eventListener;
this.events = events;
this.autostop = autostop;
}
#endregion
#region Properties
// TODO: Replace booleans with a state?
/// <summary>
/// Returns true if we are pumping events
/// </summary>
public bool Pumping
{
get { return pumping; }
}
/// <summary>
/// Returns true if a stop is in progress
/// </summary>
public bool Stopping
{
get { return stopping; }
}
#endregion
#region Public Methods
/// <summary>
/// Dispose stops the pump
/// </summary>
public void Dispose()
{
Stop();
}
/// <summary>
/// Start the pump
/// </summary>
public void Start()
{
if ( !this.Pumping ) // Ignore if already started
{
this.pumpThread = new Thread( new ThreadStart( PumpThreadProc ) );
this.pumpThread.Name = "EventPumpThread";
pumping = true;
this.pumpThread.Start();
}
}
/// <summary>
/// Tell the pump to stop after emptying the queue.
/// </summary>
public void Stop()
{
if ( this.Pumping && !this.Stopping ) // Ignore extra calls
{
lock( events )
{
stopping = true;
Monitor.Pulse( events ); // In case thread is waiting
}
this.pumpThread.Join();
}
}
#endregion
#region PumpThreadProc
/// <summary>
/// Our thread proc for removing items from the event
/// queue and sending them on. Note that this would
/// need to do more locking if any other thread were
/// removing events from the queue.
/// </summary>
private void PumpThreadProc()
{
EventListener hostListeners = CoreExtensions.Host.Listeners;
Monitor.Enter( events );
try
{
while (this.events.Count > 0 || !stopping)
{
while (this.events.Count > 0)
{
Event e = this.events.Dequeue();
e.Send(this.eventListener);
e.Send(hostListeners);
if (autostop && e is RunFinishedEvent)
stopping = true;
}
// Will be pulsed if there are any events added
// or if it's time to stop the pump.
if (!stopping)
Monitor.Wait(events);
}
}
catch (Exception ex)
{
throw new ApplicationException("Exception in pump thread", ex);
}
finally
{
Monitor.Exit( events );
pumping = false;
stopping = false;
//pumpThread = null;
}
}
#endregion
}
}

View File

@@ -0,0 +1,195 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using System.Threading;
namespace NUnit.Core
{
#region Individual Event Classes
/// <summary>
/// NUnit.Core.Event is the abstract base for all stored events.
/// An Event is the stored representation of a call to the
/// EventListener interface and is used to record such calls
/// or to queue them for forwarding on another thread or at
/// a later time.
/// </summary>
public abstract class Event
{
abstract public void Send( EventListener listener );
}
public class RunStartedEvent : Event
{
string name;
int testCount;
public RunStartedEvent( string name, int testCount )
{
this.name = name;
this.testCount = testCount;
}
public override void Send( EventListener listener )
{
listener.RunStarted(name, testCount);
}
}
public class RunFinishedEvent : Event
{
TestResult result;
Exception exception;
public RunFinishedEvent( TestResult result )
{
this.result = result;
}
public RunFinishedEvent( Exception exception )
{
this.exception = exception;
}
public override void Send( EventListener listener )
{
if ( this.exception != null )
listener.RunFinished( this.exception );
else
listener.RunFinished( this.result );
}
}
public class TestStartedEvent : Event
{
TestName testName;
public TestStartedEvent( TestName testName )
{
this.testName = testName;
}
public override void Send( EventListener listener )
{
listener.TestStarted( this.testName );
}
}
public class TestFinishedEvent : Event
{
TestCaseResult result;
public TestFinishedEvent( TestCaseResult result )
{
this.result = result;
}
public override void Send( EventListener listener )
{
listener.TestFinished( this.result );
}
}
public class SuiteStartedEvent : Event
{
TestName suiteName;
public SuiteStartedEvent( TestName suiteName )
{
this.suiteName = suiteName;
}
public override void Send( EventListener listener )
{
listener.SuiteStarted( this.suiteName );
}
}
public class SuiteFinishedEvent : Event
{
TestSuiteResult result;
public SuiteFinishedEvent( TestSuiteResult result )
{
this.result = result;
}
public override void Send( EventListener listener )
{
listener.SuiteFinished( this.result );
}
}
public class UnhandledExceptionEvent : Event
{
Exception exception;
public UnhandledExceptionEvent( Exception exception )
{
this.exception = exception;
}
public override void Send( EventListener listener )
{
listener.UnhandledException( this.exception );
}
}
public class OutputEvent : Event
{
TestOutput output;
public OutputEvent( TestOutput output )
{
this.output = output;
}
public override void Send( EventListener listener )
{
listener.TestOutput( this.output );
}
}
#endregion
/// <summary>
/// Implements a queue of work items each of which
/// is queued as a WaitCallback.
/// </summary>
public class EventQueue
{
private Queue queue = new Queue();
public int Count
{
get
{
lock( this )
{
return this.queue.Count;
}
}
}
public void Enqueue( Event e )
{
lock( this )
{
this.queue.Enqueue( e );
Monitor.Pulse( this );
}
}
public Event Dequeue()
{
lock( this )
{
return (Event)this.queue.Dequeue();
}
}
}
}

View File

@@ -0,0 +1,86 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
namespace NUnit.Core.Extensibility
{
/// <summary>
/// EventListenerCollection holds multiple event listeners
/// and relays all event calls to each of them.
/// </summary>
public class EventListenerCollection : ExtensionPoint, EventListener
{
#region Constructor
public EventListenerCollection( IExtensionHost host )
: base( "EventListeners", host ) { }
#endregion
#region EventListener Members
public void RunStarted(string name, int testCount)
{
foreach( EventListener listener in extensions )
listener.RunStarted( name, testCount );
}
public void RunFinished(TestResult result)
{
foreach( EventListener listener in extensions )
listener.RunFinished( result );
}
public void RunFinished(Exception exception)
{
foreach( EventListener listener in extensions )
listener.RunFinished( exception );
}
public void SuiteStarted(TestName testName)
{
foreach( EventListener listener in extensions )
listener.SuiteStarted( testName );
}
public void SuiteFinished(TestSuiteResult result)
{
foreach( EventListener listener in extensions )
listener.SuiteFinished( result );
}
public void TestStarted(TestName testName)
{
foreach( EventListener listener in extensions )
listener.TestStarted( testName );
}
public void TestFinished(TestCaseResult result)
{
foreach( EventListener listener in extensions )
listener.TestFinished( result );
}
public void UnhandledException(Exception exception)
{
foreach( EventListener listener in extensions )
listener.UnhandledException( exception );
}
public void TestOutput(TestOutput testOutput)
{
foreach( EventListener listener in extensions )
listener.TestOutput( testOutput );
}
#endregion
#region ExtensionPoint Overrides
protected override bool ValidExtension(object extension)
{
return extension is EventListener;
}
#endregion
}
}

View File

@@ -0,0 +1,60 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Reflection;
using System.Collections;
namespace NUnit.Core.Extensibility
{
public class FrameworkRegistry : IFrameworkRegistry
{
#region Instance Fields
/// <summary>
/// List of FrameworkInfo structs for supported frameworks
/// </summary>
private Hashtable testFrameworks = new Hashtable();
#endregion
#region IFrameworkRegistry Members
/// <summary>
/// Register a framework. NUnit registers itself using this method. Add-ins that
/// work with or emulate a different framework may register themselves as well.
/// </summary>
/// <param name="frameworkName">The name of the framework</param>
/// <param name="assemblyName">The name of the assembly that framework users reference</param>
public void Register(string frameworkName, string assemblyName)
{
testFrameworks[frameworkName] = new TestFramework(frameworkName, assemblyName);
}
#endregion
#region Other Methods
/// <summary>
/// Get a list of known frameworks referenced by an assembly
/// </summary>
/// <param name="assembly">The assembly to be examined</param>
/// <returns>A list of AssemblyNames</returns>
public IList GetReferencedFrameworks(Assembly assembly)
{
ArrayList referencedAssemblies = new ArrayList();
foreach (AssemblyName assemblyRef in assembly.GetReferencedAssemblies())
{
foreach (TestFramework info in testFrameworks.Values)
{
if (assemblyRef.Name == info.AssemblyName)
{
referencedAssemblies.Add(assemblyRef);
break;
}
}
}
return referencedAssemblies;
}
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More