private MethodInfo GetMethodInfoUsingRuntimeMethods(TestMethod testMethod, TestClassInfo testClassInfo) { MethodInfo testMethodInfo; var methodsInClass = testClassInfo.ClassType.GetRuntimeMethods().ToArray(); if (testMethod.DeclaringClassFullName != null) { // Only find methods that match the given declaring name. testMethodInfo = methodsInClass.Where(method => method.Name.Equals(testMethod.Name) && method.DeclaringType.FullName.Equals(testMethod.DeclaringClassFullName) && method.HasCorrectTestMethodSignature(true)).FirstOrDefault(); } else { // Either the declaring class is the same as the test class, or // the declaring class information wasn't passed in the test case. // Prioritize the former while maintaining previous behavior for the latter. var className = testClassInfo.ClassType.FullName; testMethodInfo = methodsInClass.Where(method => method.Name.Equals(testMethod.Name) && method.HasCorrectTestMethodSignature(true)) .OrderByDescending(method => method.DeclaringType.FullName.Equals(className)).FirstOrDefault(); } return(testMethodInfo); }
/// <summary> /// Resolve the test method. The function will try to /// find a function that has the method name with 0 parameters. If the function /// cannot be found, or a function is found that returns non-void, the result is /// set to error. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <param name="testContext"> The test Context. </param> /// <param name="captureDebugTraces"> Indicates whether the test method should capture debug traces.</param> /// <returns> /// The TestMethodInfo for the given test method. Null if the test method could not be found. /// </returns> private TestMethodInfo ResolveTestMethod(TestMethod testMethod, TestClassInfo testClassInfo, ITestContext testContext, bool captureDebugTraces) { Debug.Assert(testMethod != null, "testMethod is Null"); Debug.Assert(testClassInfo != null, "testClassInfo is Null"); var methodInfo = this.GetMethodInfoForTestMethod(testMethod, testClassInfo); if (methodInfo == null) { // Means the specified test method could not be found. return(null); } var expectedExceptionAttribute = this.reflectionHelper.ResolveExpectedExceptionHelper(methodInfo, testMethod); var timeout = this.GetTestTimeout(methodInfo, testMethod); var testMethodOptions = new TestMethodOptions() { Timeout = timeout, Executor = this.GetTestMethodAttribute(methodInfo, testClassInfo), ExpectedException = expectedExceptionAttribute, TestContext = testContext, CaptureDebugTraces = captureDebugTraces }; var testMethodInfo = new TestMethodInfo(methodInfo, testClassInfo, testMethodOptions); this.SetCustomProperties(testMethodInfo, testContext); return(testMethodInfo); }
/// <summary> /// Resolves a method by using the method name. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <returns> The <see cref="MethodInfo"/>. </returns> private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo) { var methodsInClass = testClassInfo.ClassType.GetRuntimeMethods().ToArray(); MethodInfo testMethodInfo; if (testMethod.DeclaringClassFullName != null) { // Only find methods that match the given declaring name. testMethodInfo = methodsInClass.Where(method => method.Name.Equals(testMethod.Name) && method.DeclaringType.FullName.Equals(testMethod.DeclaringClassFullName) && method.HasCorrectTestMethodSignature(true)).FirstOrDefault(); } else { // Either the declaring class is the same as the test class, or // the declaring class information wasn't passed in the test case. // Prioritize the former while maintaining previous behavior for the latter. var className = testClassInfo.ClassType.FullName; testMethodInfo = methodsInClass.Where(method => method.Name.Equals(testMethod.Name) && method.HasCorrectTestMethodSignature(true)) .OrderByDescending(method => method.DeclaringType.FullName.Equals(className)).FirstOrDefault(); } // if correct method is not found, throw appropriate // exception about what is wrong. if (testMethodInfo == null) { var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name); throw new TypeInspectionException(errorMessage); } return(testMethodInfo); }
/// <summary> /// Update the classInfo if the parameter method is a testInitialize/cleanup method /// </summary> /// <param name="classInfo"> The class Info. </param> /// <param name="methodInfo"> The method Info. </param> /// <param name="isBase"> If this needs to validate in base class or not. </param> /// <param name="instanceMethods"> The instance Methods. </param> /// <param name="testInitializeAttributeType"> The test Initialize Attribute Type. </param> /// <param name="testCleanupAttributeType"> The test Cleanup Attribute Type. </param> private void UpdateInfoIfTestInitializeOrCleanupMethod( TestClassInfo classInfo, MethodInfo methodInfo, bool isBase, Dictionary <string, string> instanceMethods, Type testInitializeAttributeType, Type testCleanupAttributeType) { var hasTestInitialize = this.reflectionHelper.IsAttributeDefined(methodInfo, testInitializeAttributeType, inherit: false); var hasTestCleanup = this.reflectionHelper.IsAttributeDefined(methodInfo, testCleanupAttributeType, inherit: false); if (!hasTestCleanup && !hasTestInitialize) { if (methodInfo.HasCorrectTestInitializeOrCleanupSignature()) { instanceMethods[methodInfo.Name] = null; } return; } if (!methodInfo.HasCorrectTestInitializeOrCleanupSignature()) { var message = string.Format(CultureInfo.CurrentCulture, Resource.UTA_TestInitializeAndCleanupMethodHasWrongSignature, methodInfo.DeclaringType.FullName, methodInfo.Name); throw new TypeInspectionException(message); } if (hasTestInitialize) { if (!isBase) { classInfo.TestInitializeMethod = methodInfo; } else { if (!instanceMethods.ContainsKey(methodInfo.Name)) { classInfo.BaseTestInitializeMethodsQueue.Enqueue(methodInfo); } } } if (hasTestCleanup) { if (!isBase) { classInfo.TestCleanupMethod = methodInfo; } else { if (!instanceMethods.ContainsKey(methodInfo.Name)) { classInfo.BaseTestCleanupMethodsQueue.Enqueue(methodInfo); } } } instanceMethods[methodInfo.Name] = null; }
/// <summary> /// Provides the Test Method Extension Attribute of the TestClass. /// </summary> /// <param name="methodInfo"> The method info. </param> /// <param name="testClassInfo"> The test class info. </param> /// <returns>Test Method Attribute</returns> private TestMethodAttribute GetTestMethodAttribute(MethodInfo methodInfo, TestClassInfo testClassInfo) { // Get the derived TestMethod attribute from reflection var testMethodAttribute = this.reflectionHelper.GetDerivedAttribute <TestMethodAttribute>(methodInfo, false); // Get the derived TestMethod attribute from Extended TestClass Attribute // If the extended TestClass Attribute doesn't have extended TestMethod attribute then base class returns back the original testMethod Attribute testMethodAttribute = testClassInfo.ClassAttribute.GetTestMethodAttribute(testMethodAttribute) ?? testMethodAttribute; return(testMethodAttribute); }
internal TestMethodInfo( MethodInfo testMethod, TestClassInfo parent, TestMethodOptions testmethodOptions) { Debug.Assert(testMethod != null, "TestMethod should not be null"); Debug.Assert(parent != null, "Parent should not be null"); this.TestMethod = testMethod; this.Parent = parent; this.TestMethodOptions = testmethodOptions; }
/// <summary> /// Update the classInfo with given initialize and cleanup methods. /// </summary> /// <param name="classInfo"> The Class Info. </param> /// <param name="initAndCleanupMethods"> An array with the Initialize and Cleanup Methods Info. </param> private void UpdateInfoWithInitializeAndCleanupMethods( TestClassInfo classInfo, ref MethodInfo[] initAndCleanupMethods) { if (initAndCleanupMethods.Any(x => x != null)) { classInfo.BaseClassInitAndCleanupMethods.Enqueue( new Tuple <MethodInfo, MethodInfo>( initAndCleanupMethods.FirstOrDefault(), initAndCleanupMethods.LastOrDefault())); } initAndCleanupMethods = new MethodInfo[2]; }
internal TestMethodInfo( MethodInfo testMethod, TestClassInfo parent, TestMethodOptions testmethodOptions, TestExecutionRecorderWrapper testExecutionRecorder) { Debug.Assert(testMethod != null, "TestMethod should not be null"); Debug.Assert(parent != null, "Parent should not be null"); Debug.Assert(testExecutionRecorder != null, "TestExecutionRecorder should not be null"); this.TestMethod = testMethod; this.Parent = parent; this.TestMethodOptions = testmethodOptions; this.TestExecutionRecorder = testExecutionRecorder; }
/// <summary> /// Resolves a method by using the method name. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <returns> The <see cref="MethodInfo"/>. </returns> private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo) { var testMethodInfo = testMethod.HasManagedMethodAndTypeProperties ? this.GetMethodInfoUsingManagedNameHelper(testMethod, testClassInfo) : this.GetMethodInfoUsingRuntimeMethods(testMethod, testClassInfo); // if correct method is not found, throw appropriate // exception about what is wrong. if (testMethodInfo == null) { var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name); throw new TypeInspectionException(errorMessage); } return(testMethodInfo); }
/// <summary> /// Update the classInfo with given initialize and cleanup methods. /// </summary> /// <param name="classInfo"> The Class Info. </param> /// <param name="initAndCleanupMethods"> An array with the Initialize and Cleanup Methods Info. </param> private void UpdateInfoWithInitializeAndCleanupMethods( TestClassInfo classInfo, ref MethodInfo[] initAndCleanupMethods) { if (initAndCleanupMethods is null) { return; } classInfo.BaseClassInitAndCleanupMethods.Enqueue( new Tuple <MethodInfo, MethodInfo>( initAndCleanupMethods.FirstOrDefault(), initAndCleanupMethods.LastOrDefault())); initAndCleanupMethods = null; }
/// <summary> /// Update the classInfo if the parameter method is a classInitialize/cleanup method /// </summary> /// <param name="classInfo"> The Class Info. </param> /// <param name="methodInfo"> The Method Info. </param> /// <param name="isBase"> Flag to check whether base class needs to be validated. </param> /// <param name="initAndCleanupMethods"> An array with Initialize/Cleanup methods. </param> /// <param name="classInitializeAttributeType"> The Class Initialize Attribute Type. </param> /// <param name="classCleanupAttributeType"> The Class Cleanup Attribute Type. </param> private void UpdateInfoIfClassInitializeOrCleanupMethod( TestClassInfo classInfo, MethodInfo methodInfo, bool isBase, ref MethodInfo[] initAndCleanupMethods, Type classInitializeAttributeType, Type classCleanupAttributeType) { var isInitializeMethod = this.IsAssemblyOrClassInitializeMethod(methodInfo, classInitializeAttributeType); var isCleanupMethod = this.IsAssemblyOrClassCleanupMethod(methodInfo, classCleanupAttributeType); if (isInitializeMethod) { if (isBase) { if (((ClassInitializeAttribute)this.reflectionHelper.GetCustomAttribute(methodInfo, classInitializeAttributeType)) .InheritanceBehavior == InheritanceBehavior.BeforeEachDerivedClass) { initAndCleanupMethods[0] = methodInfo; } } else { // update class initialize method classInfo.ClassInitializeMethod = methodInfo; } } if (isCleanupMethod) { if (isBase) { if (((ClassCleanupAttribute)this.reflectionHelper.GetCustomAttribute(methodInfo, classCleanupAttributeType)) .InheritanceBehavior == InheritanceBehavior.BeforeEachDerivedClass) { initAndCleanupMethods[1] = methodInfo; } } else { // update class cleanup method classInfo.ClassCleanupMethod = methodInfo; } } }
internal TestMethodInfo( MethodInfo testMethod, int timeout, TestMethodAttribute executor, ExpectedExceptionBaseAttribute expectedException, TestClassInfo parent, ITestContext testContext) { Debug.Assert(testMethod != null, "TestMethod should not be null"); Debug.Assert(parent != null, "Parent should not be null"); this.TestMethod = testMethod; this.Timeout = timeout; this.Parent = parent; this.ExpectedException = expectedException; this.Executor = executor; this.testContext = testContext; }
/// <summary> /// Resolves a method by using the method name. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <returns> The <see cref="MethodInfo"/>. </returns> private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo) { var methodsInClass = testClassInfo.ClassType.GetRuntimeMethods().ToArray(); var testMethodInfo = methodsInClass.Where(method => method.Name.Equals(testMethod.Name)) .FirstOrDefault(method => method.HasCorrectTestMethodSignature(true)); // if correct method is not found, throw appropriate // exception about what is wrong. if (testMethodInfo == null) { var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name); throw new TypeInspectionException(errorMessage); } return(testMethodInfo); }
/// <summary> /// Resolves a method by using the method name. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <returns> The <see cref="MethodInfo"/>. </returns> private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo) { var discoverInternals = this.discoverInternalsCache.GetOrAdd( testMethod.AssemblyName, _ => testClassInfo.Parent.Assembly.GetCustomAttribute <DiscoverInternalsAttribute>() != null); var testMethodInfo = testMethod.HasManagedMethodAndTypeProperties ? this.GetMethodInfoUsingManagedNameHelper(testMethod, testClassInfo, discoverInternals) : this.GetMethodInfoUsingRuntimeMethods(testMethod, testClassInfo, discoverInternals); // if correct method is not found, throw appropriate // exception about what is wrong. if (testMethodInfo == null) { var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name); throw new TypeInspectionException(errorMessage); } return(testMethodInfo); }
private MethodInfo GetMethodInfoUsingManagedNameHelper(TestMethod testMethod, TestClassInfo testClassInfo) { MethodInfo testMethodInfo = null; var methodBase = ManagedNameHelper.GetMethod(testClassInfo.Parent.Assembly, testMethod.ManagedTypeName, testMethod.ManagedMethodName); if (methodBase is MethodInfo mi) { testMethodInfo = mi; } else if (methodBase != null) { var parameters = methodBase.GetParameters().Select(i => i.ParameterType).ToArray(); testMethodInfo = methodBase.DeclaringType.GetRuntimeMethod(methodBase.Name, parameters); } testMethodInfo = testMethodInfo?.HasCorrectTestMethodSignature(true) ?? false ? testMethodInfo : null; return(testMethodInfo); }
/// <summary> /// Create the class Info /// </summary> /// <param name="classType"> The class Type. </param> /// <param name="testMethod"> The test Method. </param> /// <returns> The <see cref="TestClassInfo"/>. </returns> private TestClassInfo CreateClassInfo(Type classType, TestMethod testMethod) { var constructors = classType.GetTypeInfo().DeclaredConstructors; var constructor = constructors.FirstOrDefault(ctor => ctor.GetParameters().Length == 0 && ctor.IsPublic); if (constructor == null) { var message = string.Format(CultureInfo.CurrentCulture, Resource.UTA_NoDefaultConstructor, testMethod.FullClassName); throw new TypeInspectionException(message); } var testContextProperty = this.ResolveTestContext(classType); var assemblyInfo = this.GetAssemblyInfo(classType); var classInfo = new TestClassInfo(classType, constructor, testContextProperty, this.reflectionHelper.GetDerivedAttribute <TestClassAttribute>(classType, false), assemblyInfo); var testInitializeAttributeType = typeof(TestInitializeAttribute); var testCleanupAttributeType = typeof(TestCleanupAttribute); var classInitializeAttributeType = typeof(ClassInitializeAttribute); var classCleanupAttributeType = typeof(ClassCleanupAttribute); // List holding the instance of the initialize/cleanup methods // to be passed into the tuples' queue when updating the class info. var initAndCleanupMethods = new MethodInfo[2]; // List of instance methods present in the type as well its base type // which is used to decide whether TestInitialize/TestCleanup methods // present in the base type should be used or not. They are not used if // the method is overridden in the derived type. var instanceMethods = new Dictionary <string, string>(); foreach (var methodInfo in classType.GetTypeInfo().DeclaredMethods) { // Update test initialize/cleanup method this.UpdateInfoIfTestInitializeOrCleanupMethod(classInfo, methodInfo, isBase: false, instanceMethods: instanceMethods, testInitializeAttributeType: testInitializeAttributeType, testCleanupAttributeType: testCleanupAttributeType); // Update class initialize/cleanup method this.UpdateInfoIfClassInitializeOrCleanupMethod(classInfo, methodInfo, false, ref initAndCleanupMethods, classInitializeAttributeType, classCleanupAttributeType); } var baseType = classType.GetTypeInfo().BaseType; while (baseType != null) { foreach (var methodInfo in baseType.GetTypeInfo().DeclaredMethods) { if (methodInfo.IsPublic && !methodInfo.IsStatic) { // Update test initialize/cleanup method from base type. this.UpdateInfoIfTestInitializeOrCleanupMethod(classInfo, methodInfo, true, instanceMethods, testInitializeAttributeType, testCleanupAttributeType); } if (methodInfo.IsPublic && methodInfo.IsStatic) { this.UpdateInfoIfClassInitializeOrCleanupMethod(classInfo, methodInfo, true, ref initAndCleanupMethods, classInitializeAttributeType, classCleanupAttributeType); } } this.UpdateInfoWithInitializeAndCleanupMethods(classInfo, ref initAndCleanupMethods); baseType = baseType.GetTypeInfo().BaseType; } return(classInfo); }