1
// ***********************************************************************
2
// Copyright (c) 2007 Charlie Poole
4
// Permission is hereby granted, free of charge, to any person obtaining
5
// a copy of this software and associated documentation files (the
6
// "Software"), to deal in the Software without restriction, including
7
// without limitation the rights to use, copy, modify, merge, publish,
8
// distribute, sublicense, and/or sell copies of the Software, and to
9
// permit persons to whom the Software is furnished to do so, subject to
10
// the following conditions:
12
// The above copyright notice and this permission notice shall be
13
// included in all copies or substantial portions of the Software.
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
// ***********************************************************************
26
using System.Threading;
27
using System.Collections;
28
using System.Collections.Specialized;
29
//using NUnit.Core.Filters;
30
using System.Reflection;
35
/// SimpleTestRunner is the simplest direct-running TestRunner. It
36
/// passes the event listener interface that is provided on to the tests
37
/// to use directly and does nothing to redirect text output. Both
38
/// Run and BeginRun are actually synchronous, although the client
39
/// can usually ignore this. BeginRun + EndRun operates as expected.
41
public class SimpleTestRunner : MarshalByRefObject, TestRunner
43
static Logger log = InternalTrace.GetLogger(typeof(SimpleTestRunner));
45
#region Instance Variables
48
/// Identifier for this runner. Must be unique among all
49
/// active runners in order to locate tests. Default
50
/// value of 0 is adequate in applications with a single
51
/// runner or a non-branching chain of runners.
53
private int runnerID = 0;
56
/// The loaded test suite
61
/// The builder we use to load tests, created for each load
63
private TestSuiteBuilder builder;
66
/// Results from the last test run
68
private TestResult testResult;
71
/// The thread on which Run was called. Set to the
72
/// current thread while a run is in process.
74
private Thread runThread;
79
public SimpleTestRunner() : this( 0 ) { }
81
public SimpleTestRunner( int runnerID )
83
this.runnerID = runnerID;
90
get { return runnerID; }
93
public TestAssemblyInfo[] AssemblyInfo
95
get { return builder.AssemblyInfo; }
104
/// Results from the last test run
106
public TestResult TestResult
108
get { return testResult; }
111
public virtual bool Running
113
get { return runThread != null && runThread.IsAlive; }
117
#region Methods for Loading Tests
119
/// Load a TestPackage
121
/// <param name="package">The package to be loaded</param>
122
/// <returns>True on success, false on failure</returns>
123
public bool Load( TestPackage package )
125
log.Debug("Loading package " + package.Name);
127
this.builder = new TestSuiteBuilder();
129
this.test = builder.Build( package );
130
if ( test == null ) return false;
132
test.SetRunnerID( this.runnerID, true );
137
/// Unload all tests previously loaded
141
log.Debug("Unloading");
142
this.test = null; // All for now
146
#region CountTestCases
147
public int CountTestCases( TestFilter filter )
149
return test.CountTestCases( filter );
153
#region Methods for Running Tests
154
public virtual TestResult Run( ITestListener listener )
156
return Run( listener, TestFilter.Empty );
159
public virtual TestResult Run( ITestListener listener, TestFilter filter )
163
log.Debug("Starting test run");
165
// Take note of the fact that we are running
166
this.runThread = Thread.CurrentThread;
168
listener.RunStarted( this.Test.TestName, test.CountTestCases( filter ) );
170
testResult = test.Run( listener, filter );
172
// Signal that we are done
173
listener.RunFinished( testResult );
174
log.Debug("Test run complete");
176
// Return result array
179
catch( Exception exception )
181
// Signal that we finished with an exception
182
listener.RunFinished( exception );
183
// Rethrow - should we do this?
192
public void BeginRun( ITestListener listener )
194
testResult = this.Run( listener );
197
public void BeginRun( ITestListener listener, TestFilter filter )
199
testResult = this.Run( listener, filter );
202
public virtual TestResult EndRun()
208
/// Wait is a NOP for SimpleTestRunner
210
public virtual void Wait()
214
public virtual void CancelRun()
216
if (this.runThread != null)
218
// Cancel Synchronous run only if on another thread
219
if ( runThread == Thread.CurrentThread )
220
throw new InvalidOperationException( "May not CancelRun on same thread that is running the test" );
222
// Make a copy of runThread, which will be set to
223
// null when the thread terminates.
224
Thread cancelThread = this.runThread;
226
// Tell the thread to abort
227
this.runThread.Abort();
229
// Wake up the thread if necessary
230
// Figure out if we need to do an interupt
231
if ( (cancelThread.ThreadState & ThreadState.WaitSleepJoin ) != 0 )
232
cancelThread.Interrupt();
237
#region InitializeLifetimeService Override
238
public override object InitializeLifetimeService()