1 // ***********************************************************************
2 // Copyright (c) 2007-2012 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Reflection;
33 using NUnit.Compatibility;
34 using NUnit.Framework.Interfaces;
40 namespace NUnit.Framework.Internal
43 /// Helper methods for inspecting a type by reflection.
45 /// Many of these methods take ICustomAttributeProvider as an
46 /// argument to avoid duplication, even though certain attributes can
47 /// only appear on specific types of members, like MethodInfo or Type.
49 /// In the case where a type is being examined for the presence of
50 /// an attribute, interface or named member, the Reflect methods
51 /// operate with the full name of the member being sought. This
52 /// removes the necessity of the caller having a reference to the
53 /// assembly that defines the item being sought and allows the
54 /// NUnit core to inspect assemblies that reference an older
55 /// version of the NUnit framework.
57 public static class Reflect
59 private static readonly BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
61 // A zero-length Type array - not provided by System.Type for all CLR versions we support.
62 private static readonly Type[] EmptyTypes = new Type[0];
64 #region Get Methods of a type
67 /// Examine a fixture type and return an array of methods having a
68 /// particular attribute. The array is order with base methods first.
70 /// <param name="fixtureType">The type to examine</param>
71 /// <param name="attributeType">The attribute Type to look for</param>
72 /// <param name="inherit">Specifies whether to search the fixture type inheritance chain</param>
73 /// <returns>The array of methods found</returns>
74 public static MethodInfo[] GetMethodsWithAttribute(Type fixtureType, Type attributeType, bool inherit)
76 List<MethodInfo> list = new List<MethodInfo>();
79 if (fixtureType.IsGenericTypeDefinition)
81 var genArgs = fixtureType.GetGenericArguments();
82 Type[] args = new Type[genArgs.Length];
83 for (int ix = 0; ix < genArgs.Length; ++ix)
85 args[ix] = typeof(object);
88 fixtureType = fixtureType.MakeGenericType(args);
92 var flags = AllMembers | (inherit ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
93 foreach (MethodInfo method in fixtureType.GetMethods(flags))
95 if (method.IsDefined(attributeType, inherit))
99 list.Sort(new BaseTypesFirstComparer());
101 return list.ToArray();
104 private class BaseTypesFirstComparer : IComparer<MethodInfo>
106 public int Compare(MethodInfo m1, MethodInfo m2)
108 if (m1 == null || m2 == null) return 0;
110 Type m1Type = m1.DeclaringType;
111 Type m2Type = m2.DeclaringType;
113 if ( m1Type == m2Type ) return 0;
114 if ( m1Type.IsAssignableFrom(m2Type) ) return -1;
121 /// Examine a fixture type and return true if it has a method with
122 /// a particular attribute.
124 /// <param name="fixtureType">The type to examine</param>
125 /// <param name="attributeType">The attribute Type to look for</param>
126 /// <returns>True if found, otherwise false</returns>
127 public static bool HasMethodWithAttribute(Type fixtureType, Type attributeType)
130 return fixtureType.GetMethods(AllMembers | BindingFlags.FlattenHierarchy)
131 .Any(m => m.GetCustomAttributes(false).Any(a => attributeType.IsAssignableFrom(a.GetType())));
135 if (fixtureType.ContainsGenericParameters)
138 foreach (MethodInfo method in fixtureType.GetMethods(AllMembers | BindingFlags.FlattenHierarchy))
140 if (method.IsDefined(attributeType, false))
149 #region Invoke Constructors
152 /// Invoke the default constructor on a Type
154 /// <param name="type">The Type to be constructed</param>
155 /// <returns>An instance of the Type</returns>
156 public static object Construct(Type type)
158 ConstructorInfo ctor = type.GetConstructor(EmptyTypes);
160 throw new InvalidTestFixtureException(type.FullName + " does not have a default constructor");
162 return ctor.Invoke(null);
166 /// Invoke a constructor on a Type with arguments
168 /// <param name="type">The Type to be constructed</param>
169 /// <param name="arguments">Arguments to the constructor</param>
170 /// <returns>An instance of the Type</returns>
171 public static object Construct(Type type, object[] arguments)
173 if (arguments == null) return Construct(type);
175 Type[] argTypes = GetTypeArray(arguments);
176 ITypeInfo typeInfo = new TypeWrapper(type);
177 ConstructorInfo ctor = typeInfo.GetConstructor(argTypes);
179 throw new InvalidTestFixtureException(type.FullName + " does not have a suitable constructor");
181 return ctor.Invoke(arguments);
185 /// Returns an array of types from an array of objects.
186 /// Used because the compact framework doesn't support
187 /// Type.GetTypeArray()
189 /// <param name="objects">An array of objects</param>
190 /// <returns>An array of Types</returns>
191 internal static Type[] GetTypeArray(object[] objects)
193 Type[] types = new Type[objects.Length];
195 foreach (object o in objects)
197 // NUnitNullType is a marker to indicate null since we can't do typeof(null) or null.GetType()
198 types[index++] = o == null ? typeof(NUnitNullType) : o.GetType();
205 #region Invoke Methods
208 /// Invoke a parameterless method returning void on an object.
210 /// <param name="method">A MethodInfo for the method to be invoked</param>
211 /// <param name="fixture">The object on which to invoke the method</param>
212 public static object InvokeMethod( MethodInfo method, object fixture )
214 return InvokeMethod(method, fixture, null);
218 /// Invoke a method, converting any TargetInvocationException to an NUnitException.
220 /// <param name="method">A MethodInfo for the method to be invoked</param>
221 /// <param name="fixture">The object on which to invoke the method</param>
222 /// <param name="args">The argument list for the method</param>
223 /// <returns>The return value from the invoked method</returns>
224 public static object InvokeMethod( MethodInfo method, object fixture, params object[] args )
230 return method.Invoke(fixture, args);
233 catch (System.Threading.ThreadAbortException)
235 // No need to wrap or rethrow ThreadAbortException
239 catch (TargetInvocationException e)
241 throw new NUnitException("Rethrown", e.InnerException);
245 throw new NUnitException("Rethrown", e);