/src/NUnit/core/SimpleTestRunner.cs

# · C# · 235 lines · 139 code · 40 blank · 56 comment · 13 complexity · a89d5c5f41f93e1d823469abc3242eae MD5 · raw file

  1. // ****************************************************************
  2. // Copyright 2007, Charlie Poole
  3. // This is free software licensed under the NUnit license. You may
  4. // obtain a copy of the license at http://nunit.org.
  5. // ****************************************************************
  6. using System;
  7. using System.IO;
  8. using System.Threading;
  9. using System.Collections;
  10. using System.Collections.Specialized;
  11. using NUnit.Core.Filters;
  12. using System.Reflection;
  13. namespace NUnit.Core
  14. {
  15. /// <summary>
  16. /// SimpleTestRunner is the simplest direct-running TestRunner. It
  17. /// passes the event listener interface that is provided on to the tests
  18. /// to use directly and does nothing to redirect text output. Both
  19. /// Run and BeginRun are actually synchronous, although the client
  20. /// can usually ignore this. BeginRun + EndRun operates as expected.
  21. /// </summary>
  22. public class SimpleTestRunner : MarshalByRefObject, TestRunner
  23. {
  24. static Logger log = InternalTrace.GetLogger(typeof(SimpleTestRunner));
  25. #region Instance Variables
  26. /// <summary>
  27. /// Identifier for this runner. Must be unique among all
  28. /// active runners in order to locate tests. Default
  29. /// value of 0 is adequate in applications with a single
  30. /// runner or a non-branching chain of runners.
  31. /// </summary>
  32. private int runnerID = 0;
  33. /// <summary>
  34. /// The loaded test suite
  35. /// </summary>
  36. private Test test;
  37. /// <summary>
  38. /// The builder we use to load tests, created for each load
  39. /// </summary>
  40. private TestSuiteBuilder builder;
  41. /// <summary>
  42. /// Results from the last test run
  43. /// </summary>
  44. private TestResult testResult;
  45. /// <summary>
  46. /// The thread on which Run was called. Set to the
  47. /// current thread while a run is in process.
  48. /// </summary>
  49. private Thread runThread;
  50. #endregion
  51. #region Constructor
  52. public SimpleTestRunner() : this( 0 ) { }
  53. public SimpleTestRunner( int runnerID )
  54. {
  55. this.runnerID = runnerID;
  56. }
  57. #endregion
  58. #region Properties
  59. public virtual int ID
  60. {
  61. get { return runnerID; }
  62. }
  63. public IList AssemblyInfo
  64. {
  65. get { return builder.AssemblyInfo; }
  66. }
  67. public ITest Test
  68. {
  69. get { return test == null ? null : new TestNode( test ); }
  70. }
  71. /// <summary>
  72. /// Results from the last test run
  73. /// </summary>
  74. public TestResult TestResult
  75. {
  76. get { return testResult; }
  77. }
  78. public virtual bool Running
  79. {
  80. get { return runThread != null && runThread.IsAlive; }
  81. }
  82. #endregion
  83. #region Methods for Loading Tests
  84. /// <summary>
  85. /// Load a TestPackage
  86. /// </summary>
  87. /// <param name="package">The package to be loaded</param>
  88. /// <returns>True on success, false on failure</returns>
  89. public bool Load( TestPackage package )
  90. {
  91. log.Debug("Loading package " + package.Name);
  92. this.builder = new TestSuiteBuilder();
  93. this.test = builder.Build( package );
  94. if ( test == null ) return false;
  95. test.SetRunnerID( this.runnerID, true );
  96. return true;
  97. }
  98. /// <summary>
  99. /// Unload all tests previously loaded
  100. /// </summary>
  101. public void Unload()
  102. {
  103. log.Debug("Unloading");
  104. this.test = null; // All for now
  105. }
  106. #endregion
  107. #region CountTestCases
  108. public int CountTestCases( ITestFilter filter )
  109. {
  110. return test.CountTestCases( filter );
  111. }
  112. #endregion
  113. #region Methods for Running Tests
  114. public virtual TestResult Run( EventListener listener )
  115. {
  116. return Run( listener, TestFilter.Empty );
  117. }
  118. public virtual TestResult Run( EventListener listener, ITestFilter filter )
  119. {
  120. try
  121. {
  122. log.Debug("Starting test run");
  123. // Take note of the fact that we are running
  124. this.runThread = Thread.CurrentThread;
  125. listener.RunStarted( this.Test.TestName.FullName, test.CountTestCases( filter ) );
  126. testResult = test.Run( listener, filter );
  127. // Signal that we are done
  128. listener.RunFinished( testResult );
  129. log.Debug("Test run complete");
  130. // Return result array
  131. return testResult;
  132. }
  133. catch( Exception exception )
  134. {
  135. // Signal that we finished with an exception
  136. listener.RunFinished( exception );
  137. // Rethrow - should we do this?
  138. throw;
  139. }
  140. finally
  141. {
  142. runThread = null;
  143. }
  144. }
  145. public void BeginRun( EventListener listener )
  146. {
  147. testResult = this.Run( listener );
  148. }
  149. public void BeginRun( EventListener listener, ITestFilter filter )
  150. {
  151. testResult = this.Run( listener, filter );
  152. }
  153. public virtual TestResult EndRun()
  154. {
  155. return TestResult;
  156. }
  157. /// <summary>
  158. /// Wait is a NOP for SimpleTestRunner
  159. /// </summary>
  160. public virtual void Wait()
  161. {
  162. }
  163. public virtual void CancelRun()
  164. {
  165. if (this.runThread != null)
  166. {
  167. // Cancel Synchronous run only if on another thread
  168. if ( runThread == Thread.CurrentThread )
  169. throw new InvalidOperationException( "May not CancelRun on same thread that is running the test" );
  170. // Make a copy of runThread, which will be set to
  171. // null when the thread terminates.
  172. Thread cancelThread = this.runThread;
  173. // Tell the thread to abort
  174. this.runThread.Abort();
  175. // Wake up the thread if necessary
  176. // Figure out if we need to do an interupt
  177. if ( (cancelThread.ThreadState & ThreadState.WaitSleepJoin ) != 0 )
  178. cancelThread.Interrupt();
  179. }
  180. }
  181. #endregion
  182. #region InitializeLifetimeService Override
  183. public override object InitializeLifetimeService()
  184. {
  185. return null;
  186. }
  187. #endregion
  188. #region IDisposable Members
  189. public void Dispose()
  190. {
  191. Unload();
  192. }
  193. #endregion
  194. }
  195. }