PageRenderTime 38ms CodeModel.GetById 15ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/core/NUnitFramework.cs

#
C# | 437 lines | 322 code | 46 blank | 69 comment | 62 complexity | 60add14917d41755daf5fd107b307bbc 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.Reflection;
  8using System.Collections;
  9using System.Collections.Specialized;
 10using System.Diagnostics;
 11using NUnit.Core.Extensibility;
 12
 13namespace NUnit.Core
 14{
 15	/// <summary>
 16	/// Static methods that implement aspects of the NUnit framework that cut 
 17	/// across individual test types, extensions, etc. Some of these use the 
 18	/// methods of the Reflect class to implement operations specific to the 
 19	/// NUnit Framework.
 20	/// </summary>
 21	public class NUnitFramework
 22	{
 23        #region Constants
 24
 25		#region Attribute Names
 26		// NOTE: Attributes used in switch statements must be const
 27
 28        // Attributes that apply to Assemblies, Classes and Methods
 29        public const string IgnoreAttribute = "NUnit.Framework.IgnoreAttribute";
 30		public const string PlatformAttribute = "NUnit.Framework.PlatformAttribute";
 31		public const string CultureAttribute = "NUnit.Framework.CultureAttribute";
 32		public const string ExplicitAttribute = "NUnit.Framework.ExplicitAttribute";
 33        public const string CategoryAttribute = "NUnit.Framework.CategoryAttribute";
 34        public const string PropertyAttribute = "NUnit.Framework.PropertyAttribute";
 35		public const string DescriptionAttribute = "NUnit.Framework.DescriptionAttribute";
 36        public const string RequiredAddinAttribute = "NUnit.Framework.RequiredAddinAttribute";
 37
 38        // Attributes that apply only to Classes
 39        public const string TestFixtureAttribute = "NUnit.Framework.TestFixtureAttribute";
 40        public const string SetUpFixtureAttribute = "NUnit.Framework.SetUpFixtureAttribute";
 41
 42        // Attributes that apply only to Methods
 43        public const string TestAttribute = "NUnit.Framework.TestAttribute";
 44        public const string TestCaseAttribute = "NUnit.Framework.TestCaseAttribute";
 45        public const string TestCaseSourceAttribute = "NUnit.Framework.TestCaseSourceAttribute";
 46        public const string TheoryAttribute = "NUnit.Framework.TheoryAttribute";
 47        public static readonly string SetUpAttribute = "NUnit.Framework.SetUpAttribute";
 48        public static readonly string TearDownAttribute = "NUnit.Framework.TearDownAttribute";
 49        public static readonly string FixtureSetUpAttribute = "NUnit.Framework.TestFixtureSetUpAttribute";
 50        public static readonly string FixtureTearDownAttribute = "NUnit.Framework.TestFixtureTearDownAttribute";
 51        public static readonly string ExpectedExceptionAttribute = "NUnit.Framework.ExpectedExceptionAttribute";
 52
 53        // Attributes that apply only to Properties
 54        public static readonly string SuiteAttribute = "NUnit.Framework.SuiteAttribute";
 55        #endregion
 56
 57        #region Other Framework Types
 58        public static readonly string AssertException = "NUnit.Framework.AssertionException";
 59        public static readonly string IgnoreException = "NUnit.Framework.IgnoreException";
 60        public static readonly string InconclusiveException = "NUnit.Framework.InconclusiveException";
 61        public static readonly string SuccessException = "NUnit.Framework.SuccessException";
 62        public static readonly string AssertType = "NUnit.Framework.Assert";
 63		public static readonly string ExpectExceptionInterface = "NUnit.Framework.IExpectException";
 64        #endregion
 65
 66        #region Core Types
 67        public static readonly string SuiteBuilderAttribute = typeof(SuiteBuilderAttribute).FullName;
 68        public static readonly string SuiteBuilderInterface = typeof(ISuiteBuilder).FullName;
 69
 70        public static readonly string TestCaseBuilderAttributeName = typeof(TestCaseBuilderAttribute).FullName;
 71        public static readonly string TestCaseBuilderInterfaceName = typeof(ITestCaseBuilder).FullName;
 72
 73        public static readonly string TestDecoratorAttributeName = typeof(TestDecoratorAttribute).FullName;
 74        public static readonly string TestDecoratorInterfaceName = typeof(ITestDecorator).FullName;
 75        #endregion
 76
 77        #endregion
 78
 79        #region Properties
 80        private static Assembly frameworkAssembly;
 81        private static bool frameworkAssemblyInitialized;
 82        private static Assembly FrameworkAssembly
 83        {
 84            get
 85            {
 86                if (!frameworkAssemblyInitialized)
 87                    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
 88                        if (assembly.GetName().Name == "nunit.framework" ||
 89                            assembly.GetName().Name == "NUnitLite")
 90                        {
 91                            frameworkAssembly = assembly;
 92                            break;
 93                        }
 94
 95                frameworkAssemblyInitialized = true;
 96
 97                return frameworkAssembly;
 98            }
 99        }
100        #endregion
101
102        #region Check SetUp and TearDown methods
103        public static bool CheckSetUpTearDownMethods(Type fixtureType, string attributeName, ref string reason)
104        {
105            foreach( MethodInfo theMethod in Reflect.GetMethodsWithAttribute(fixtureType, attributeName, true ))
106                if ( theMethod.IsAbstract ||
107                     !theMethod.IsPublic && !theMethod.IsFamily ||
108                     theMethod.GetParameters().Length > 0 ||
109                     !theMethod.ReturnType.Equals(typeof(void)))
110                {
111                    reason = string.Format( "Invalid signature for SetUp or TearDown method: {0}", theMethod.Name );
112                    return false;
113                }
114
115            return true;
116        }
117        #endregion
118
119        #region Get Special Properties of Attributes
120
121        #region IgnoreReason
122        public static string GetIgnoreReason( System.Attribute attribute )
123		{
124            return Reflect.GetPropertyValue(attribute, PropertyNames.Reason) as string;
125		}
126		#endregion
127
128		#region Description
129		/// <summary>
130		/// Method to return the description from an source
131		/// </summary>
132		/// <param name="source">The source to check</param>
133		/// <returns>The description, if any, or null</returns>
134		public static string GetDescription(System.Attribute attribute)
135		{
136            return Reflect.GetPropertyValue(attribute, PropertyNames.Description) as string;
137		}
138		#endregion
139
140		#endregion
141
142		#region ApplyCommonAttributes
143        /// <summary>
144        /// Modify a newly constructed test based on a type or method by 
145        /// applying any of NUnit's common attributes.
146        /// </summary>
147        /// <param name="member">The type or method from which the test was constructed</param>
148        /// <param name="test">The test to which the attributes apply</param>
149        public static void ApplyCommonAttributes(MemberInfo member, Test test)
150        {
151            ApplyCommonAttributes( Reflect.GetAttributes( member, true ), test );
152        }
153
154        /// <summary>
155        /// Modify a newly constructed test based on an assembly by applying 
156        /// any of NUnit's common attributes.
157        /// </summary>
158        /// <param name="assembly">The assembly from which the test was constructed</param>
159        /// <param name="test">The test to which the attributes apply</param>
160        public static void ApplyCommonAttributes(Assembly assembly, Test test)
161        {
162            ApplyCommonAttributes( Reflect.GetAttributes( assembly, false ), test );
163        }
164
165        /// <summary>
166        /// Modify a newly constructed test by applying any of NUnit's common
167        /// attributes, based on an input array of attributes. This method checks
168        /// for all attributes, relying on the fact that specific attributes can only
169        /// occur on those constructs on which they are allowed.
170        /// </summary>
171        /// <param name="attributes">An array of attributes possibly including NUnit attributes
172        /// <param name="test">The test to which the attributes apply</param>
173        public static void ApplyCommonAttributes(Attribute[] attributes, Test test)
174        {
175            foreach (Attribute attribute in attributes)
176            {
177				Type attributeType = attribute.GetType();
178				string attributeName = attributeType.FullName;
179                bool isValid = test.RunState != RunState.NotRunnable;
180
181                switch (attributeName)
182                {
183					case TestFixtureAttribute:
184					case TestAttribute:
185						if ( test.Description == null )
186							test.Description = GetDescription( attribute );
187						break;
188					case DescriptionAttribute:
189						test.Description = GetDescription( attribute );
190						break;
191                    case PlatformAttribute:
192                        PlatformHelper pHelper = new PlatformHelper();
193                        if (isValid && !pHelper.IsPlatformSupported(attribute))
194                        {
195                            test.RunState = RunState.Skipped;
196                            test.IgnoreReason = GetIgnoreReason(attribute);
197							if ( test.IgnoreReason == null )
198								test.IgnoreReason = pHelper.Reason;
199                        }
200                        break;
201					case CultureAttribute:
202						CultureDetector cultureDetector = new CultureDetector();
203						if (isValid && !cultureDetector.IsCultureSupported(attribute))
204						{
205							test.RunState = RunState.Skipped;
206							test.IgnoreReason = cultureDetector.Reason;
207						}
208						break;
209                    case RequiredAddinAttribute:
210                        string required = (string)Reflect.GetPropertyValue(attribute, PropertyNames.RequiredAddin);
211                        if (!IsAddinAvailable(required))
212                        {
213                            test.RunState = RunState.NotRunnable;
214                            test.IgnoreReason = string.Format("Required addin {0} not available", required);
215                        }
216                        break;
217                    case "System.STAThreadAttribute":
218                        test.Properties.Add("APARTMENT_STATE", System.Threading.ApartmentState.STA);
219                        break;
220                    case "System.MTAThreadAttribute":
221                        test.Properties.Add("APARTMENT_STATE", System.Threading.ApartmentState.MTA);
222                        break;
223                    default:
224						if ( Reflect.InheritsFrom( attributeType, CategoryAttribute ) )
225						{
226                            string categoryName = (string)Reflect.GetPropertyValue(attribute, PropertyNames.CategoryName);
227                            test.Categories.Add(categoryName);
228
229                            if (categoryName.IndexOfAny(new char[] { ',', '!', '+', '-' }) >= 0)
230                            {
231                                test.RunState = RunState.NotRunnable;
232                                test.IgnoreReason = "Category name must not contain ',', '!', '+' or '-'";
233                            }
234                        }
235						else if ( Reflect.InheritsFrom( attributeType, PropertyAttribute ) )
236						{
237							IDictionary props = (IDictionary)Reflect.GetPropertyValue( attribute, PropertyNames.Properties );
238							if ( props != null )
239                                foreach( DictionaryEntry entry in props )
240                                    test.Properties.Add(entry.Key, entry.Value);
241						}
242                        else if ( Reflect.InheritsFrom( attributeType, ExplicitAttribute ) )
243                         {
244                             if (isValid)
245                             {
246                                 test.RunState = RunState.Explicit;
247                                 test.IgnoreReason = GetIgnoreReason(attribute);
248                             }
249                         }
250                         else if ( Reflect.InheritsFrom( attributeType, IgnoreAttribute ) )
251                         {
252                             if (isValid)
253                             {
254                                 test.RunState = RunState.Ignored;
255                                 test.IgnoreReason = GetIgnoreReason(attribute);
256                             }
257                         }
258						break;
259                }
260            }
261        }
262		#endregion
263
264        #region ApplyExpectedExceptionAttribute
265        /// <summary>
266        /// Modify a newly constructed test by checking for ExpectedExceptionAttribute
267        /// and setting properties on the test accordingly.
268        /// </summary>
269        /// <param name="attributes">An array of attributes possibly including NUnit attributes
270        /// <param name="test">The test to which the attributes apply</param>
271        public static void ApplyExpectedExceptionAttribute(MethodInfo method, TestMethod testMethod)
272        {
273            Attribute attribute = Reflect.GetAttribute(
274                method, NUnitFramework.ExpectedExceptionAttribute, false);
275
276            if (attribute != null)
277                testMethod.ExceptionProcessor = new ExpectedExceptionProcessor(testMethod, attribute);
278        }
279
280        #endregion
281
282        #region IsSuiteBuilder
283        public static bool IsSuiteBuilder( Type type )
284		{
285			return Reflect.HasAttribute( type, SuiteBuilderAttribute, false )
286				&& Reflect.HasInterface( type, SuiteBuilderInterface );
287		}
288		#endregion
289
290		#region IsTestCaseBuilder
291		public static bool IsTestCaseBuilder( Type type )
292		{
293			return Reflect.HasAttribute( type, TestCaseBuilderAttributeName, false )
294				&& Reflect.HasInterface( type, TestCaseBuilderInterfaceName );
295		}
296		#endregion
297
298		#region IsTestDecorator
299		public static bool IsTestDecorator( Type type )
300		{
301			return Reflect.HasAttribute( type, TestDecoratorAttributeName, false )
302				&& Reflect.HasInterface( type, TestDecoratorInterfaceName );
303		}
304		#endregion
305
306        #region IsAddinAvailable
307        public static bool IsAddinAvailable(string name)
308        {
309            foreach (Addin addin in CoreExtensions.Host.AddinRegistry.Addins)
310                if (addin.Name == name && addin.Status == AddinStatus.Loaded)
311                    return true;
312
313            return false;
314        }
315        #endregion
316
317        #region Framework Assert Access
318
319        /// <summary>
320        /// NUnitFramework.Assert is a nested class that implements
321        /// a few of the framework operations by reflection, 
322        /// using whatever framework version is available.
323        /// </summary>
324        public class Assert
325        {
326            #region Properties
327            private static Type assertType;
328            private static Type AssertType
329            {
330                get
331                {
332                    if (assertType == null && FrameworkAssembly != null)
333                        assertType = FrameworkAssembly.GetType(NUnitFramework.AssertType);
334
335                    return assertType;
336                }
337            }
338
339            private static MethodInfo areEqualMethod;
340            private static MethodInfo AreEqualMethod
341            {
342                get
343                {
344                    if (areEqualMethod == null && AssertType != null)
345                        areEqualMethod = AssertType.GetMethod(
346                            "AreEqual", 
347                            BindingFlags.Static | BindingFlags.Public, 
348                            null, 
349                            new Type[] { typeof(object), typeof(object) },
350                            null );
351
352                    return areEqualMethod;
353                }
354            }
355
356            private static PropertyInfo counterProperty;
357            private static PropertyInfo CounterProperty
358            {
359                get
360                {
361                    if (counterProperty == null && AssertType != null)
362                        counterProperty = Reflect.GetNamedProperty(
363                            AssertType,
364                            "Counter",
365                            BindingFlags.Public | BindingFlags.Static);
366
367                    return counterProperty;
368                }
369            }
370            #endregion
371
372            /// <summary>
373            /// Invoke Assert.AreEqual by reflection
374            /// </summary>
375            /// <param name="expected">The expected value</param>
376            /// <param name="actual">The actual value</param>
377            public static void AreEqual(object expected, object actual)
378            {
379                if (AreEqualMethod != null)
380                    try
381                    {
382                        AreEqualMethod.Invoke(null, new object[] { expected, actual });
383                    }
384                    catch (TargetInvocationException e)
385                    {
386                        Exception inner = e.InnerException;
387                        throw new NUnitException("Rethrown", inner);
388                    }
389            }
390
391            /// <summary>
392            /// Get the assertion counter. It clears itself automatically
393            /// on each call.
394            /// </summary>
395            /// <returns>Count of number of asserts since last call</returns>
396            public static int GetAssertCount()
397            {
398                return CounterProperty == null
399                    ? 0
400                    : (int)CounterProperty.GetValue(null, new object[0]);
401            }
402        }
403
404        #endregion
405
406        #region GetResultState
407        /// <summary>
408        /// Returns a result state for a special exception.
409        /// If the exception is not handled specially, returns
410        /// ResultState.Error.
411        /// </summary>
412        /// <param name="ex">The exception to be examined</param>
413        /// <returns>A ResultState</returns>
414        public static ResultState GetResultState(Exception ex)
415        {
416            if (ex is System.Threading.ThreadAbortException)
417                return ResultState.Cancelled;
418
419            string name = ex.GetType().FullName;
420
421            if (name == NUnitFramework.AssertException)
422                return ResultState.Failure;
423            else
424                if (name == NUnitFramework.IgnoreException)
425                    return ResultState.Ignored;
426                else
427                    if (name == NUnitFramework.InconclusiveException)
428                        return ResultState.Inconclusive;
429                    else
430                        if (name == NUnitFramework.SuccessException)
431                            return ResultState.Success;
432                        else
433                            return ResultState.Error;
434        }
435        #endregion
436    }
437}