/// <summary> /// Checks if the given class is marked as <see cref="TestFixtureAttribute"/> and does not contain at least one <see cref="TestAttribute"/> method. /// </summary> /// <param name="type"> The test class type. </param> /// <returns> false if the given class is marked as <see cref="TestFixtureAttribute"/> and does not contain at least one <see cref="TestAttribute"/> method, true otherwise. </returns> public override bool CompileTimeValidate(Type type) { if (TypeInvestigationService.IsConcreteContextSpecification(type) && !TypeInvestigationService.GetAllTestMethods(type).Any()) { return ErrorService.RaiseError(this.GetType(), type, string.Format("{0} does not contain any tests. Concrete ContextSpecifications must contain tests", type.Name)); } return true; }
/// <summary> /// Checks that there is no private field in given class if this is abstract. /// </summary> /// <param name="type"> The class to be checked.</param> /// <returns>Raises an error if there is any private field in given class if this is abstract.</returns> public override bool CompileTimeValidate(Type type) { try { const BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Static; if (type.IsAbstract) { var fields = type.GetFields(Flags).Where(f => f.IsPrivate).ToList(); if (fields.Any()) { var field = fields.First(); return(ErrorService.RaiseError(this.GetType(), type, string.Format("{0} should be a protected property.\r\n", field.Name))); } } } catch (Exception e) { return(ErrorService.RaiseError(this.GetType(), type, e.Message)); } return(true); }
/// <summary> /// Verifies that base.EstablishContext is always called. /// </summary> /// <param name="type"> The class to be checked. </param> /// <returns> The System.Boolean. </returns> /// <remarks> /// Intermediate language interpretation is very limited in this method. /// WARN: Could produce false positive/negative due to intermediate byte array analysis. /// Could detect more calls to EstablishContext than exists. /// </remarks> public override bool CompileTimeValidate(Type type) { // ReSharper disable once InvertIf if (TypeInvestigationService.GetAllTestMethods(type).Any()) { try { var methodInfo = type.GetMethod("EstablishContext", BindingFlags.Instance | BindingFlags.NonPublic); if (methodInfo != null) { var establishContextDeclaringType = methodInfo.DeclaringType; var intermediateLanguage = GetIntermediateLanguageFromMethodInfo(methodInfo); if (establishContextDeclaringType == null) { return(false); } var position = 0; var baseEstablishContextCalls = 0; var anotherEstablishContextCalls = 0; while (position < intermediateLanguage.Length) { switch (intermediateLanguage[position++]) { case CallInstructionCode: { if (position + 3 < intermediateLanguage.Length) { var metadataToken = ((intermediateLanguage[position] | (intermediateLanguage[position + 1] << 8)) | (intermediateLanguage[position + 2] << 0x10)) | (intermediateLanguage[position + 3] << 0x18); var calledMethod = GetMethodBaseFromIntermediateLanguage(metadataToken, establishContextDeclaringType, methodInfo); if (calledMethod != null && calledMethod.Name == "EstablishContext") { var establishContextCalledClassType = calledMethod.DeclaringType; if (establishContextCalledClassType != null && establishContextDeclaringType.IsSubclassOf(establishContextCalledClassType)) { baseEstablishContextCalls++; } else { anotherEstablishContextCalls++; } position += 4; } else { position++; } } else { position++; } break; } } } if (baseEstablishContextCalls == 1) { return(true); } if (baseEstablishContextCalls == 0) { if (anotherEstablishContextCalls > 0) { return(ErrorService.RaiseError(this.GetType(), type, "The EstablishContext of the '{0}' class calls another EstablishContext than the base.EstablishContext.\r\n\r\nPlease replace EstablishContext call in the EstablishContext method of the '{0}' class.\r\n")); } if (establishContextDeclaringType != typeof(ContextSpecificationBase) && (establishContextDeclaringType.IsGenericType && establishContextDeclaringType.GetGenericTypeDefinition() != typeof(SubjectInstantiationContextSpecification <>))) { return(ErrorService.RaiseError(this.GetType(), type, string.Format("The EstablishContext of the '{0}' class does not call the base.EstablishContext.\r\n\r\nPlease add base.EstablishContext in the EstablishContext method of the '{{0}}' class.\r\n", establishContextDeclaringType.Name))); } } if (baseEstablishContextCalls > 1) { return(ErrorService.RaiseError(this.GetType(), type, "The EstablishContext of the '{0}' class calls the base.EstablishContext many times.\r\n\r\nPlease remove unneeded base.EstablishContext in the EstablishContext method of the '{0}' class.\r\n")); } } } catch (Exception e) { return(ErrorService.RaiseError(this.GetType(), type, string.Format("Error occurs while processing type {{0}}: {0}", e.Message))); } } return(true); }