/// <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);
        }
Exemple #3
0
        /// <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);
        }