PageRenderTime 46ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/core/TestExecutionContext.cs

#
C# | 423 lines | 234 code | 56 blank | 133 comment | 22 complexity | 1c4b573bb6ebbf5d8b8a5bcf2b3a9f62 MD5 | raw file
Possible License(s): GPL-2.0
  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.Collections.Specialized;
  8. using System.Configuration;
  9. using System.IO;
  10. using System.Diagnostics;
  11. using System.Globalization;
  12. using System.Security.Principal;
  13. using System.Threading;
  14. namespace NUnit.Core
  15. {
  16. /// <summary>
  17. /// Helper class used to save and restore certain static or
  18. /// singleton settings in the environment that affect tests
  19. /// or which might be changed by the user tests.
  20. ///
  21. /// An internal class is used to hold settings and a stack
  22. /// of these objects is pushed and popped as Save and Restore
  23. /// are called.
  24. ///
  25. /// Static methods for each setting forward to the internal
  26. /// object on the top of the stack.
  27. /// </summary>
  28. public class TestExecutionContext
  29. {
  30. #region Static Fields
  31. /// <summary>
  32. /// The current context, head of the list of saved contexts.
  33. /// </summary>
  34. private static TestExecutionContext current = new TestExecutionContext();
  35. #endregion
  36. #region Instance Fields
  37. /// <summary>
  38. /// Indicates whether trace is enabled
  39. /// </summary>
  40. private bool tracing;
  41. /// <summary>
  42. /// Indicates whether logging is enabled
  43. /// </summary>
  44. private bool logging;
  45. /// <summary>
  46. /// Destination for standard output
  47. /// </summary>
  48. private TextWriter outWriter;
  49. /// <summary>
  50. /// Destination for standard error
  51. /// </summary>
  52. private TextWriter errorWriter;
  53. /// <summary>
  54. /// Destination for Trace output
  55. /// </summary>
  56. private TextWriter traceWriter;
  57. /// <summary>
  58. /// Default timeout for test cases
  59. /// </summary>
  60. private int testCaseTimeout;
  61. private Log4NetCapture logCapture;
  62. /// <summary>
  63. /// The current working directory
  64. /// </summary>
  65. private string currentDirectory;
  66. /// <summary>
  67. /// The current culture
  68. /// </summary>
  69. private CultureInfo currentCulture;
  70. /// <summary>
  71. /// The current UI culture
  72. /// </summary>
  73. private CultureInfo currentUICulture;
  74. /// <summary>
  75. /// The current Principal.
  76. /// </summary>
  77. private IPrincipal currentPrincipal;
  78. /// <summary>
  79. /// The currently executing test
  80. /// </summary>
  81. private Test currentTest;
  82. /// <summary>
  83. /// The active TestResult for the current test
  84. /// </summary>
  85. private TestResult currentResult;
  86. /// <summary>
  87. /// Link to a prior saved context
  88. /// </summary>
  89. public TestExecutionContext prior;
  90. #endregion
  91. #region Constructors
  92. /// <summary>
  93. /// Initializes a new instance of the <see cref="TestExecutionContext"/> class.
  94. /// </summary>
  95. public TestExecutionContext()
  96. {
  97. this.prior = null;
  98. this.tracing = false;
  99. this.logging = false;
  100. this.outWriter = Console.Out;
  101. this.errorWriter = Console.Error;
  102. this.traceWriter = null;
  103. this.logCapture = new Log4NetCapture();
  104. this.testCaseTimeout = 0;
  105. this.currentDirectory = Environment.CurrentDirectory;
  106. this.currentCulture = CultureInfo.CurrentCulture;
  107. this.currentUICulture = CultureInfo.CurrentUICulture;
  108. this.currentPrincipal = Thread.CurrentPrincipal;
  109. }
  110. /// <summary>
  111. /// Initializes a new instance of the <see cref="TestExecutionContext"/> class.
  112. /// </summary>
  113. /// <param name="other">An existing instance of TestExecutionContext.</param>
  114. public TestExecutionContext(TestExecutionContext other)
  115. {
  116. this.prior = other;
  117. this.tracing = other.tracing;
  118. this.logging = other.logging;
  119. this.outWriter = other.outWriter;
  120. this.errorWriter = other.errorWriter;
  121. this.traceWriter = other.traceWriter;
  122. this.logCapture = other.logCapture;
  123. this.testCaseTimeout = other.testCaseTimeout;
  124. this.currentTest = other.currentTest;
  125. this.currentResult = other.currentResult;
  126. this.currentDirectory = Environment.CurrentDirectory;
  127. this.currentCulture = CultureInfo.CurrentCulture;
  128. this.currentUICulture = CultureInfo.CurrentUICulture;
  129. this.currentPrincipal = Thread.CurrentPrincipal;
  130. }
  131. #endregion
  132. #region Static Singleton Instance
  133. /// <summary>
  134. /// Gets the current context.
  135. /// </summary>
  136. /// <value>The current context.</value>
  137. public static TestExecutionContext CurrentContext
  138. {
  139. get { return current; }
  140. }
  141. #endregion
  142. #region Properties
  143. /// <summary>
  144. /// Controls whether trace and debug output are written
  145. /// to the standard output.
  146. /// </summary>
  147. public bool Tracing
  148. {
  149. get { return tracing; }
  150. set
  151. {
  152. if (tracing != value)
  153. {
  154. if (traceWriter != null && tracing)
  155. StopTracing();
  156. tracing = value;
  157. if (traceWriter != null && tracing)
  158. StartTracing();
  159. }
  160. }
  161. }
  162. /// <summary>
  163. /// Controls whether log output is captured
  164. /// </summary>
  165. public bool Logging
  166. {
  167. get { return logCapture.Enabled; }
  168. set { logCapture.Enabled = value; }
  169. }
  170. /// <summary>
  171. /// Controls where Console.Out is directed
  172. /// </summary>
  173. public TextWriter Out
  174. {
  175. get { return outWriter; }
  176. set
  177. {
  178. if (outWriter != value)
  179. {
  180. outWriter = value;
  181. Console.Out.Flush();
  182. Console.SetOut(outWriter);
  183. }
  184. }
  185. }
  186. /// <summary>
  187. /// Controls where Console.Error is directed
  188. /// </summary>
  189. public TextWriter Error
  190. {
  191. get { return errorWriter; }
  192. set
  193. {
  194. if (errorWriter != value)
  195. {
  196. errorWriter = value;
  197. Console.Error.Flush();
  198. Console.SetError(errorWriter);
  199. }
  200. }
  201. }
  202. /// <summary>
  203. /// Controls where Trace output is directed
  204. /// </summary>
  205. public TextWriter TraceWriter
  206. {
  207. get { return traceWriter; }
  208. set
  209. {
  210. if (traceWriter != value)
  211. {
  212. if (traceWriter != null && tracing)
  213. StopTracing();
  214. traceWriter = value;
  215. if (traceWriter != null && tracing)
  216. StartTracing();
  217. }
  218. }
  219. }
  220. /// <summary>
  221. /// Gets or sets the Log writer, which is actually held by a log4net
  222. /// TextWriterAppender. When first set, the appender will be created
  223. /// and will thereafter send any log events to the writer.
  224. ///
  225. /// In normal operation, LogWriter is set to an EventListenerTextWriter
  226. /// connected to the EventQueue in the test domain. The events are
  227. /// subsequently captured in the Gui an the output displayed in
  228. /// the Log tab. The application under test does not need to define
  229. /// any additional appenders.
  230. /// </summary>
  231. public TextWriter LogWriter
  232. {
  233. get { return logCapture.Writer; }
  234. set { logCapture.Writer = value; }
  235. }
  236. private void StopTracing()
  237. {
  238. traceWriter.Close();
  239. System.Diagnostics.Trace.Listeners.Remove("NUnit");
  240. }
  241. private void StartTracing()
  242. {
  243. System.Diagnostics.Trace.Listeners.Add(new TextWriterTraceListener(traceWriter, "NUnit"));
  244. }
  245. /// <summary>
  246. /// Saves and restores the CurrentDirectory
  247. /// </summary>
  248. public string CurrentDirectory
  249. {
  250. get { return currentDirectory; }
  251. set
  252. {
  253. currentDirectory = value;
  254. Environment.CurrentDirectory = currentDirectory;
  255. }
  256. }
  257. /// <summary>
  258. /// Saves or restores the CurrentCulture
  259. /// </summary>
  260. public CultureInfo CurrentCulture
  261. {
  262. get { return currentCulture; }
  263. set
  264. {
  265. currentCulture = value;
  266. Thread.CurrentThread.CurrentCulture = currentCulture;
  267. }
  268. }
  269. /// <summary>
  270. /// Saves or restores the CurrentUICulture
  271. /// </summary>
  272. public CultureInfo CurrentUICulture
  273. {
  274. get { return currentUICulture; }
  275. set
  276. {
  277. currentUICulture = value;
  278. Thread.CurrentThread.CurrentUICulture = currentUICulture;
  279. }
  280. }
  281. /// <summary>
  282. /// Gets or sets the current <see cref="IPrincipal"/> for the Thread.
  283. /// </summary>
  284. public IPrincipal CurrentPrincipal
  285. {
  286. get { return this.currentPrincipal; }
  287. set
  288. {
  289. this.currentPrincipal = value;
  290. Thread.CurrentPrincipal = this.currentPrincipal;
  291. }
  292. }
  293. /// <summary>
  294. /// Gets or sets the test case timeout vaue
  295. /// </summary>
  296. public int TestCaseTimeout
  297. {
  298. get { return testCaseTimeout; }
  299. set { testCaseTimeout = value; }
  300. }
  301. /// <summary>
  302. /// Gets or sets the current test
  303. /// </summary>
  304. public Test CurrentTest
  305. {
  306. get { return currentTest; }
  307. set { currentTest = value; }
  308. }
  309. /// <summary>
  310. /// Gets or sets the current test result
  311. /// </summary>
  312. public TestResult CurrentResult
  313. {
  314. get { return currentResult; }
  315. set { currentResult = value; }
  316. }
  317. #endregion
  318. #region Static Methods
  319. /// <summary>
  320. /// Saves the old context and makes a fresh one
  321. /// current without changing any settings.
  322. /// </summary>
  323. public static void Save()
  324. {
  325. TestExecutionContext.current = new TestExecutionContext(current);
  326. }
  327. /// <summary>
  328. /// Restores the last saved context and puts
  329. /// any saved settings back into effect.
  330. /// </summary>
  331. public static void Restore()
  332. {
  333. current.ReverseChanges();
  334. current = current.prior;
  335. }
  336. #endregion
  337. #region Instance Methods
  338. /// <summary>
  339. /// Used to restore settings to their prior
  340. /// values before reverting to a prior context.
  341. /// </summary>
  342. public void ReverseChanges()
  343. {
  344. if (prior == null)
  345. throw new InvalidOperationException("TestContext: too many Restores");
  346. this.Tracing = prior.Tracing;
  347. this.Out = prior.Out;
  348. this.Error = prior.Error;
  349. this.CurrentDirectory = prior.CurrentDirectory;
  350. this.CurrentCulture = prior.CurrentCulture;
  351. this.CurrentUICulture = prior.CurrentUICulture;
  352. this.TestCaseTimeout = prior.TestCaseTimeout;
  353. this.CurrentPrincipal = prior.CurrentPrincipal;
  354. }
  355. /// <summary>
  356. /// Record any changed values in the current context
  357. /// </summary>
  358. public void Update()
  359. {
  360. this.currentDirectory = Environment.CurrentDirectory;
  361. this.currentCulture = CultureInfo.CurrentCulture;
  362. this.currentUICulture = CultureInfo.CurrentUICulture;
  363. this.currentPrincipal = System.Threading.Thread.CurrentPrincipal;
  364. }
  365. #endregion
  366. }
  367. }