**** Merged from MCS ****
[mono-project.git] / mcs / nunit20 / core / Reflect.cs
blob98cdfe3e380faeee504c5c259d1384678227db7b
1 using System;
2 using System.Reflection;
3 using System.Collections;
4 using NUnit.Framework;
6 namespace NUnit.Core
8 /// <summary>
9 /// Helper methods for inspecting a type by reflection.
10 ///
11 /// Many of these methods take a MemberInfo as an argument to avoid
12 /// duplication, even though certain attributes can only appear on
13 /// specific types of members, like MethodInfo or Type.
14 ///
15 /// Generally, these methods perform simple utility functions like
16 /// checking for a given attribute. However, some of the methdods
17 /// actually implement policies, which might change at some later
18 /// time. The intent is that policies that may vary among different
19 /// types of test cases or suites should be handled by those types,
20 /// while common decisions are handled here.
21 /// </summary>
22 public class Reflect
24 #region Attribute types used by reflect
26 public static readonly Type TestFixtureType = typeof( TestFixtureAttribute );
27 public static readonly Type TestType = typeof( TestAttribute );
28 public static readonly Type SetUpType = typeof( SetUpAttribute );
29 public static readonly Type TearDownType = typeof( TearDownAttribute );
30 public static readonly Type FixtureSetUpType = typeof( TestFixtureSetUpAttribute );
31 public static readonly Type FixtureTearDownType = typeof( TestFixtureTearDownAttribute );
32 public static readonly Type ExplicitType = typeof( ExplicitAttribute );
33 public static readonly Type CategoryType = typeof( CategoryAttribute );
34 public static readonly Type IgnoreType = typeof( IgnoreAttribute );
35 public static readonly Type ExpectedExceptionType = typeof( ExpectedExceptionAttribute );
36 public static readonly Type SuiteType = typeof( SuiteAttribute );
38 #endregion
40 #region Binding flags used by reflect
42 private static readonly BindingFlags InstanceMethods =
43 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
45 private static readonly BindingFlags StaticMethods =
46 BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly;
48 private static readonly BindingFlags AllMethods =
49 BindingFlags.Public | BindingFlags.NonPublic |
50 BindingFlags.Instance | BindingFlags.Static;
52 private static readonly BindingFlags AllDeclaredMethods =
53 AllMethods | BindingFlags.DeclaredOnly;
55 #endregion
57 #region Check for presence of an attribute
59 public static bool HasTestFixtureAttribute(Type type)
61 return type.IsDefined( TestFixtureType, true ); // Inheritable
64 public static bool HasTestAttribute(MethodInfo method)
66 return method.IsDefined( TestType, false );
69 public static bool HasExplicitAttribute(MemberInfo member)
71 return member.IsDefined( ExplicitType, false );
74 public static bool HasCategoryAttribute(MemberInfo member)
76 return member.IsDefined( CategoryType, false );
79 public static bool HasExpectedExceptionAttribute(MethodInfo method)
81 return method.IsDefined( ExpectedExceptionType, false );
84 public static bool HasIgnoreAttribute( MemberInfo member )
86 return member.IsDefined( IgnoreType, false );
89 public static bool HasSuiteAttribute( PropertyInfo property )
91 return property.IsDefined( SuiteType, false );
94 #endregion
96 #region Legacy Checks on Names
98 public static bool IsObsoleteTestMethod(MethodInfo methodToCheck)
100 if ( methodToCheck.Name.ToLower().StartsWith("test") )
102 object[] attributes = methodToCheck.GetCustomAttributes( false );
104 foreach( Attribute attribute in attributes )
105 if( attribute is SetUpAttribute ||
106 attribute is TestFixtureSetUpAttribute ||
107 attribute is TearDownAttribute ||
108 attribute is TestFixtureTearDownAttribute )
110 return false;
113 return true;
116 return false;
119 #endregion
121 #region Get Attributes
123 public static TestFixtureAttribute GetTestFixtureAttribute( Type type )
125 object[] attributes = type.GetCustomAttributes( TestFixtureType, true );
126 return attributes.Length > 0 ? (TestFixtureAttribute) attributes[0] : null;
129 public static TestAttribute GetTestAttribute( MemberInfo member )
131 object[] attributes = member.GetCustomAttributes( TestType, false );
132 return attributes.Length > 0 ? (TestAttribute)attributes[0] : null;
135 public static IgnoreAttribute GetIgnoreAttribute( MemberInfo member )
137 object[] attributes = member.GetCustomAttributes( IgnoreType, false );
138 return attributes.Length > 0 ? (IgnoreAttribute) attributes[0] : null;
141 public static ExpectedExceptionAttribute GetExpectedExceptionAttribute( MethodInfo method )
143 object[] attributes = method.GetCustomAttributes( ExpectedExceptionType, false);
144 return attributes.Length > 0 ? (ExpectedExceptionAttribute) attributes[0] : null;
147 #endregion
149 #region Get Properties of Attributes
151 public static string GetIgnoreReason( MemberInfo member )
153 IgnoreAttribute attribute = GetIgnoreAttribute( member );
154 return attribute == null ? "no reason" : attribute.Reason;
157 public static string GetDescription( MethodInfo method )
159 TestAttribute attribute = GetTestAttribute( method );
160 return attribute == null ? null : attribute.Description;
163 public static string GetDescription( Type fixtureType )
165 TestFixtureAttribute attribute = GetTestFixtureAttribute( fixtureType );
166 return attribute == null ? null : attribute.Description;
169 #endregion
171 #region Methods to check validity of a type and its members
173 /// <summary>
174 /// Method to validate that a type is a valid test fixture
175 /// </summary>
176 /// <param name="fixtureType">The type to be checked</param>
177 public static void CheckFixtureType( Type fixtureType )
179 if ( fixtureType.GetConstructor( Type.EmptyTypes ) == null )
180 throw new InvalidTestFixtureException(fixtureType.FullName + " does not have a valid constructor");
182 CheckSetUpTearDownMethod( fixtureType, SetUpType );
183 CheckSetUpTearDownMethod( fixtureType, TearDownType );
184 CheckSetUpTearDownMethod( fixtureType, FixtureSetUpType );
185 CheckSetUpTearDownMethod( fixtureType, FixtureTearDownType );
188 /// <summary>
189 /// This method verifies that a type has no more than one method of a particular
190 /// SetUp or TearDown type and that the method has a correct signature.
191 /// </summary>
192 /// <param name="fixtureType">The type to be checked</param>
193 /// <param name="attributeType">The attribute to check for</param>
194 private static void CheckSetUpTearDownMethod( Type fixtureType, Type attributeType )
196 int count = 0;
197 MethodInfo theMethod = null;
199 foreach(MethodInfo method in fixtureType.GetMethods( AllDeclaredMethods ))
201 if( method.IsDefined( attributeType, false ) )
203 theMethod = method;
204 count++;
208 if ( count > 1 )
210 string attributeName = attributeType.Name;
211 if ( attributeName.EndsWith( "Attribute" ) )
212 attributeName = attributeName.Substring(
213 0, attributeName.Length - 9 );
215 throw new InvalidTestFixtureException(
216 string.Format( "{0} has multiple {1} methods",
217 fixtureType.Name, attributeName ) );
220 CheckSetUpTearDownSignature( theMethod );
223 private static void CheckSetUpTearDownSignature( MethodInfo method )
225 if ( method != null )
227 if ( !method.IsPublic && !method.IsFamily || method.IsStatic || method.ReturnType != typeof(void) || method.GetParameters().Length > 0 )
228 throw new InvalidTestFixtureException("Invalid SetUp or TearDown method signature");
232 /// <summary>
233 /// Check the signature of a test method
234 /// </summary>
235 /// <param name="methodToCheck">The method signature to check</param>
236 /// <returns>True if the signature is correct, otherwise false</returns>
237 public static bool IsTestMethodSignatureCorrect(MethodInfo methodToCheck)
239 return
240 !methodToCheck.IsStatic
241 && !methodToCheck.IsAbstract
242 && methodToCheck.IsPublic
243 && methodToCheck.GetParameters().Length == 0
244 && methodToCheck.ReturnType.Equals(typeof(void));
247 #endregion
249 #region Get Methods of a type
251 // These methods all take an object and assume that the type of the
252 // object was pre-checked so that there are no duplicate methods,
253 // statics, private methods, etc.
255 public static ConstructorInfo GetConstructor( Type fixtureType )
257 return fixtureType.GetConstructor( Type.EmptyTypes );
260 public static MethodInfo GetSetUpMethod( Type fixtureType )
262 return GetMethod( fixtureType, SetUpType );
265 public static MethodInfo GetTearDownMethod(Type fixtureType)
267 return GetMethod(fixtureType, TearDownType );
270 public static MethodInfo GetFixtureSetUpMethod( Type fixtureType )
272 return GetMethod( fixtureType, FixtureSetUpType );
275 public static MethodInfo GetFixtureTearDownMethod( Type fixtureType )
277 return GetMethod( fixtureType, FixtureTearDownType );
280 public static MethodInfo GetMethod( Type fixtureType, Type attributeType )
282 foreach(MethodInfo method in fixtureType.GetMethods( InstanceMethods ) )
284 if( method.IsDefined( attributeType, true ) )
285 return method;
288 return null;
291 public static MethodInfo GetMethod( Type fixtureType, string methodName )
293 foreach(MethodInfo method in fixtureType.GetMethods( InstanceMethods ) )
295 if( method.Name == methodName )
296 return method;
299 return null;
302 #endregion
304 #region Get Suite Property
306 public static PropertyInfo GetSuiteProperty( Type testClass )
308 if( testClass != null )
310 PropertyInfo[] properties = testClass.GetProperties( StaticMethods );
311 foreach( PropertyInfo property in properties )
313 if( Reflect.HasSuiteAttribute( property ) )
315 try
317 CheckSuiteProperty(property);
319 catch( InvalidSuiteException )
321 return null;
323 return property;
327 return null;
330 private static void CheckSuiteProperty(PropertyInfo property)
332 MethodInfo method = property.GetGetMethod(true);
333 if(method.ReturnType!=typeof(NUnit.Core.TestSuite))
334 throw new InvalidSuiteException("Invalid suite property method signature");
335 if(method.GetParameters().Length>0)
336 throw new InvalidSuiteException("Invalid suite property method signature");
339 #endregion
341 #region Categories
343 public static IList GetCategories( MemberInfo member )
345 object[] attributes = member.GetCustomAttributes( CategoryType, false );
346 IList names = new ArrayList();
348 foreach(CategoryAttribute attribute in attributes)
349 names.Add(attribute.Name);
351 return names;
354 #endregion
356 #region Invoke Methods
358 public static object Construct( Type type )
360 ConstructorInfo ctor = GetConstructor( type );
361 if ( ctor == null )
362 throw new InvalidTestFixtureException(type.FullName + " does not have a valid constructor");
364 return ctor.Invoke( Type.EmptyTypes );
367 public static void InvokeMethod( MethodInfo method, object fixture )
369 if(method != null)
373 method.Invoke( fixture, null );
375 catch(TargetInvocationException e)
377 Exception inner = e.InnerException;
378 throw new NunitException("Rethrown",inner);
383 public static void InvokeSetUp( object fixture )
385 MethodInfo method = GetSetUpMethod( fixture.GetType() );
386 if(method != null)
388 InvokeMethod(method, fixture);
392 public static void InvokeTearDown( object fixture )
394 MethodInfo method = GetTearDownMethod( fixture.GetType() );
395 if(method != null)
397 InvokeMethod(method, fixture);
401 #endregion
403 #region Private Constructor for static-only class
405 private Reflect() { }
407 #endregion