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