/// <summary> /// Consumes type members including fields, properties, methods and events. /// </summary> /// <param name="typeScope">The scope to be used as the containing scope.</param> /// <param name="type">The type whose members are to be consumed.</param> protected void ConsumeMembers(IPatternScope typeScope, ITypeInfo type) { BindingFlags bindingFlags = GetMemberBindingFlags(type); // TODO: We should probably process groups of members in sorted order working outwards // from the base type, like an onion. foreach (IFieldInfo field in CodeElementSorter.SortMembersByDeclaringType(type.GetFields(bindingFlags))) { typeScope.Consume(field, false, DefaultFieldPattern); } foreach (IPropertyInfo property in CodeElementSorter.SortMembersByDeclaringType(type.GetProperties(bindingFlags))) { typeScope.Consume(property, false, DefaultPropertyPattern); } foreach (IMethodInfo method in CodeElementSorter.SortMembersByDeclaringType(type.GetMethods(bindingFlags))) { typeScope.Consume(method, false, DefaultMethodPattern); } foreach (IEventInfo @event in CodeElementSorter.SortMembersByDeclaringType(type.GetEvents(bindingFlags))) { typeScope.Consume(@event, false, DefaultEventPattern); } }
/// <summary> /// Consumes nested types. /// </summary> /// <param name="typeScope">The scope to be used as the containing scope.</param> /// <param name="type">The type whose nested types are to be consumed.</param> protected void ConsumeNestedTypes(IPatternScope typeScope, ITypeInfo type) { foreach (ITypeInfo nestedType in type.GetNestedTypes(NestedTypeBindingFlags)) { typeScope.Consume(nestedType, false, DefaultNestedTypePattern); } }
/// <inheritdoc /> public override void Consume(IPatternScope containingScope, ICodeElementInfo codeElement, bool skipChildren) { //TODO: Review: Issue 762: Shouldn't the base method be invoked here? //base.Consume(containingScope, codeElement, skipChildren); if (!IsReadableFieldOrProperty(codeElement)) { ThrowUsageErrorException("This attribute may only be applied to fields and properties with getters."); } ISlotInfo slot = (ISlotInfo)codeElement; ITypeInfo mixinType = slot.ValueType; if (!mixinType.IsClass || !AttributeUtils.HasAttribute(mixinType, typeof(MixinAttribute), true)) { ThrowUsageErrorException(String.Format("The field or property value type must be a class with the [Mixin] attribute applied. " + "The type {0} does not appear to be a valid mixin class.", mixinType)); } // TODO: Detect cycles. // TODO: Modify how fixture types and instances are interpreted in the mixin. IPatternScope mixinScope = containingScope.CreateScope(codeElement, containingScope.TestBuilder, null, containingScope.TestDataContextBuilder.CreateChild(), false); mixinScope.Consume(mixinType, skipChildren, null); }
/// <summary> /// Populates the children of the assembly test all at once. /// </summary> /// <remarks> /// <para> /// The default implementation processes all public and non-public types within the assembly. /// </para> /// </remarks> /// <param name="assemblyScope">The assembly scope.</param> /// <param name="assembly">The assembly.</param> protected virtual void PopulateChildrenImmediately(IPatternScope assemblyScope, IAssemblyInfo assembly) { foreach (ITypeInfo type in assembly.GetTypes()) { if (!type.IsNested) { assemblyScope.Consume(type, false, DefaultTypePattern); } } }
/// <summary> /// Consumes type constructors. /// </summary> /// <param name="typeScope">The scope to be used as the containing scope.</param> /// <param name="type">The type whose constructors are to be consumed.</param> protected void ConsumeConstructors(IPatternScope typeScope, ITypeInfo type) { if (ShouldConsumeConstructors(type)) { // FIXME: Currently we arbitrarily choose the first constructor and throw away the rest. // This should be replaced by a more intelligent mechanism that supports a constructor // selection policy based on some criterion. IConstructorInfo constructor = GetFirstConstructorWithPreferenceForPublicConsructor(type); if (constructor != null) { typeScope.Consume(constructor, false, DefaultConstructorPattern); } } }
/// <summary> /// Prepares to populate the children of the assembly test on demand by /// adding a deferred populator with <see cref="IPatternScope.AddDeferredComponentPopulator" />. /// </summary> /// <param name="assemblyScope">The assembly scope.</param> /// <param name="assembly">The assembly.</param> protected virtual void PrepareToPopulateChildrenOnDemand(IPatternScope assemblyScope, IAssemblyInfo assembly) { var populatedTypes = new GallioHashSet <ITypeInfo>(); assemblyScope.AddDeferredComponentPopulator(childCodeElementHint => { ITypeInfo type = childCodeElementHint as ITypeInfo; if (type != null && !type.IsNested && !populatedTypes.Contains(type) && assembly.Equals(type.Assembly)) { populatedTypes.Add(type); assemblyScope.Consume(type, false, DefaultTypePattern); } }); }
/// <summary> /// Initializes a test for a method after it has been added to the test model. /// </summary> /// <param name="methodScope">The method scope.</param> /// <param name="method">The method.</param> protected virtual void InitializeTest(IPatternScope methodScope, IMethodInfo method) { string xmlDocumentation = method.GetXmlDocumentation(); if (xmlDocumentation != null) { methodScope.TestBuilder.AddMetadata(MetadataKeys.XmlDocumentation, xmlDocumentation); } methodScope.Process(method); if (method.IsGenericMethodDefinition) { foreach (IGenericParameterInfo parameter in method.GenericArguments) { methodScope.Consume(parameter, false, DefaultGenericParameterPattern); } } foreach (IParameterInfo parameter in method.Parameters) { methodScope.Consume(parameter, false, DefaultMethodParameterPattern); } }
/// <summary> /// Initializes the <see cref="PatternTestDataContext" />. /// </summary> /// <param name="dataContextScope">The data context scope.</param> /// <param name="constructor">The constructor.</param> protected virtual void InitializeDataContext(IPatternScope dataContextScope, IConstructorInfo constructor) { ITypeInfo declaringType = constructor.DeclaringType; if (declaringType.IsGenericTypeDefinition) { dataContextScope.TestDataContextBuilder.ImplicitDataBindingIndexOffset = declaringType.GenericArguments.Count; } foreach (IParameterInfo parameter in constructor.Parameters) { dataContextScope.Consume(parameter, false, DefaultConstructorParameterPattern); } dataContextScope.Process(constructor); }
private bool BuildAssemblyTest(IAssemblyInfo assembly, bool skipChildren) { bool fullyPopulated; if (assemblies.TryGetValue(assembly, out fullyPopulated)) { return(fullyPopulated); } IList <PatternTestFrameworkExtensionInfo> extensions = extensionProvider(assembly); if (extensions.Count == 0) { fullyPopulated = true; } assemblies.Add(assembly, fullyPopulated); if (!fullyPopulated) { IPatternScope rootScope = evaluator.RootScope; InitializeAssembly(rootScope, assembly); rootScope.Consume(assembly, skipChildren, TestAssemblyPatternAttribute.DefaultInstance); foreach (PatternTest assemblyTest in evaluator.GetDeclaredTests(assembly)) { if (extensions.Count == 1 && assemblyTest.Kind == TestKinds.Assembly) { assemblyTest.Kind = extensions[0].AssemblyKind; } foreach (var extension in extensions) { assemblyTest.Metadata.Add(MetadataKeys.Framework, extension.Name); } } } return(fullyPopulated); }
/// <summary> /// Initializes a test for a type after it has been added to the test model. /// </summary> /// <remarks> /// <para> /// The members of base types are processed before those of subtypes. /// </para> /// <para> /// The default implementation processes all public members of the type including /// the first constructor found, then recurses to process all public and non-public /// nested types. Non-public members other than nested types are ignored. /// </para> /// </remarks> /// <param name="typeScope">The type scope.</param> /// <param name="type">The type.</param> protected virtual void InitializeTest(IPatternScope typeScope, ITypeInfo type) { string xmlDocumentation = type.GetXmlDocumentation(); if (xmlDocumentation != null) { typeScope.TestBuilder.AddMetadata(MetadataKeys.XmlDocumentation, xmlDocumentation); } typeScope.Process(type); if (type.IsGenericTypeDefinition) { foreach (IGenericParameterInfo parameter in type.GenericArguments) { typeScope.Consume(parameter, false, DefaultGenericParameterPattern); } } ConsumeMembers(typeScope, type); ConsumeConstructors(typeScope, type); ConsumeNestedTypes(typeScope, type); }
/// <summary> /// Initializes a test for a method after it has been added to the test model. /// </summary> /// <param name="methodScope">The method scope.</param> /// <param name="method">The method.</param> protected virtual void InitializeTest(IPatternScope methodScope, IMethodInfo method) { string xmlDocumentation = method.GetXmlDocumentation(); if (xmlDocumentation != null) methodScope.TestBuilder.AddMetadata(MetadataKeys.XmlDocumentation, xmlDocumentation); methodScope.Process(method); if (method.IsGenericMethodDefinition) { foreach (IGenericParameterInfo parameter in method.GenericArguments) methodScope.Consume(parameter, false, DefaultGenericParameterPattern); } foreach (IParameterInfo parameter in method.Parameters) methodScope.Consume(parameter, false, DefaultMethodParameterPattern); }
/// <summary> /// Initializes the <see cref="PatternTestDataContext" />. /// </summary> /// <param name="dataContextScope">The data context scope.</param> /// <param name="constructor">The constructor.</param> protected virtual void InitializeDataContext(IPatternScope dataContextScope, IConstructorInfo constructor) { ITypeInfo declaringType = constructor.DeclaringType; if (declaringType.IsGenericTypeDefinition) dataContextScope.TestDataContextBuilder.ImplicitDataBindingIndexOffset = declaringType.GenericArguments.Count; foreach (IParameterInfo parameter in constructor.Parameters) dataContextScope.Consume(parameter, false, DefaultConstructorParameterPattern); dataContextScope.Process(constructor); }
/// <summary> /// Prepares to populate the children of the assembly test on demand by /// adding a deferred populator with <see cref="IPatternScope.AddDeferredComponentPopulator" />. /// </summary> /// <param name="assemblyScope">The assembly scope.</param> /// <param name="assembly">The assembly.</param> protected virtual void PrepareToPopulateChildrenOnDemand(IPatternScope assemblyScope, IAssemblyInfo assembly) { var populatedTypes = new HashSet<ITypeInfo>(); assemblyScope.AddDeferredComponentPopulator(childCodeElementHint => { ITypeInfo type = childCodeElementHint as ITypeInfo; if (type != null && ! type.IsNested && !populatedTypes.Contains(type) && assembly.Equals(type.Assembly)) { populatedTypes.Add(type); assemblyScope.Consume(type, false, DefaultTypePattern); } }); }
/// <summary> /// Populates the children of the assembly test all at once. /// </summary> /// <remarks> /// <para> /// The default implementation processes all public and non-public types within the assembly. /// </para> /// </remarks> /// <param name="assemblyScope">The assembly scope.</param> /// <param name="assembly">The assembly.</param> protected virtual void PopulateChildrenImmediately(IPatternScope assemblyScope, IAssemblyInfo assembly) { foreach (ITypeInfo type in assembly.GetTypes()) { if (!type.IsNested) assemblyScope.Consume(type, false, DefaultTypePattern); } }