public void GetCustomAttributes_ReturnParameterInfo_ReturnsCorrectAttributes()
        {
            TestAll(info =>
            {
                var sourceMethods = info.SourceType.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                    .Where(m => m.IsSpecialName == false && !m.DeclaringType.Equals(typeof(object)));

                var infoName = info.SourceType.Name;
                foreach (var sourceMethod in sourceMethods)
                {
                    var targetMethod = info.TargetType.GetMethods().SingleOrDefault(method =>
                                                                                    method.Name == sourceMethod.Name &&
                                                                                    method.GetParameters().SequenceEqual(sourceMethod.GetParameters(), ParameterInfoComparer.Default) &&
                                                                                    method.GetGenericArguments().Length == sourceMethod.GetGenericArguments().Length
                                                                                    );

                    Assert.IsNotNull(targetMethod, $"Method {sourceMethod.Name} was not found in class {info.TargetType.Name}");


                    var sourceParameter = sourceMethod.ReturnParameter;
                    var targetParameter = targetMethod.ReturnParameter;

                    if (!sourceParameter.GetCustomAttributes(false).SequenceEqual(FilterAttributes(targetParameter.GetCustomAttributes(false))))
                    {
                        Debugger.Break();
                    }
                    SequenceAssert.AreEquivalent(sourceParameter.GetCustomAttributes(false), FilterAttributes(targetParameter.GetCustomAttributes(false)), $"Attribute mismatch on return parameter of method {sourceMethod.DeclaringType.Name}.{sourceMethod.Name}({String.Join(",", sourceMethod.GetParameters().Select(p => p.ParameterType.Name))}) (inherit=false)");
                    SequenceAssert.AreEquivalent(sourceParameter.GetCustomAttributes(true), FilterAttributes(targetParameter.GetCustomAttributes(true)), $"Attribute mismatch on return parameter of method {sourceMethod.DeclaringType.Name}.{sourceMethod.Name}({String.Join(",", sourceMethod.GetParameters().Select(p => p.ParameterType.Name))}) (inherit=true)");
                }
            });
        }
 public void GetCustomAttributes_Type_InheritIsFalse_ReturnsCorrectAttributes()
 {
     TestAll(info =>
     {
         SequenceAssert.AreEquivalent(info.SourceType.GetCustomAttributes(false), FilterAttributes(info.TargetType.GetCustomAttributes(false)), $"Attribute mismatch on type {info.SourceType.Name} (inherit=true)");
     });
 }
        public void GetCustomAttributes_EventInfo_ReturnsCorrectAttributes()
        {
            TestAll(info =>
            {
                EventInfo[] sourceEvents = info.SourceType.GetEvents(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                foreach (var sourceEvent in sourceEvents)
                {
                    var targetProperty = info.TargetType.GetEvents(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                         .SingleOrDefault(ev => ev.Name == sourceEvent.Name && ev.DeclaringType.Name == sourceEvent.DeclaringType.Name);

                    Assert.IsNotNull(targetProperty, $"Event {sourceEvent.Name} was not found in class {info.TargetType.Name}");

                    SequenceAssert.AreEquivalent(sourceEvent.GetCustomAttributes(false), FilterAttributes(targetProperty.GetCustomAttributes(false)), $"Attribute mismatch on event {sourceEvent.DeclaringType.Name}.{sourceEvent.Name} (inherit=false)");

                    bool honorInheritance = info.ReflectionContext.Options.HasFlag(TableReflectionContextOptions.HonorPropertyAttributeInheritance);

                    // The default EventInfo.GetCustomAttributes ignores the inherit flag, so we need to use the Attribute.GetCustomAttributes method
                    // to get inheritance behavior. However, this method can only be used with RuntimeTypes, so we cannot use it for the target type. Instead
                    // this is controlled via the reflection context options.
                    object[] expectedInherited = honorInheritance ? Attribute.GetCustomAttributes(sourceEvent, true) : sourceEvent.GetCustomAttributes(true);
                    SequenceAssert.AreEquivalent(expectedInherited, FilterAttributes(targetProperty.GetCustomAttributes(true)), $"Attribute mismatch on event {sourceEvent.DeclaringType.Name}.{sourceEvent.Name} (inherit=true)");
                }
            });
        }
        public void GetCustomAttributes_DuplicateAttributesWereAddedToTable_TableAttributesDisallowingMultipleOverwritesExistingAttributes()
        {
            ReflectionTableBuilder builder = new ReflectionTableBuilder();

            builder.ForType <DecoratedTypes.Base>()
            .AddTypeAttributes(new InheritedSingleAttribute("Q"), new InheritedMultiAttribute("Q"), new NonInheritedSingleAttribute("Q"), new NonInheritedMultiAttribute("Q"))
            ;

            var table   = builder.CreateTable();
            var context = new TableReflectionContext(table, TableReflectionContextOptions.Default);

            var originalType = typeof(DecoratedTypes.Base);
            var mappedType   = context.MapType(originalType);

            var expected = new Attribute[] {
                new InheritedMultiAttribute("Q"),
                new InheritedSingleAttribute("Q"),
                new NonInheritedMultiAttribute("Q"),
                new NonInheritedSingleAttribute("Q"),
                new InheritedMultiAttribute(nameof(DecoratedTypes.Base)),
                new NonInheritedMultiAttribute(nameof(DecoratedTypes.Base))
            };

            var actual = FilterAttributes(mappedType.GetCustomAttributes(true));

            SequenceAssert.AreEquivalent(expected, actual);
        }
        public void GetCustomAttributes_ChainedReflectionContexts_ReturnsExpectedAttributes()
        {
            ReflectionTableBuilder builderA = new ReflectionTableBuilder();

            builderA.ForType <DecoratedTypes.Base>()
            .AddTypeAttributes(new InheritedSingleAttribute("Q"), new InheritedMultiAttribute("Q"), new NonInheritedSingleAttribute("Q"), new NonInheritedMultiAttribute("Q"))
            .AddMemberAttributes(t => t.OverriddenProperty, new InheritedSingleAttribute("Q"), new InheritedMultiAttribute("Q"), new NonInheritedSingleAttribute("Q"), new NonInheritedMultiAttribute("Q"))
            ;

            var tableA   = builderA.CreateTable();
            var contextA = new TableReflectionContext(tableA, TableReflectionContextOptions.Default);

            var originalType = typeof(DecoratedTypes.Base);
            var mappedTypeA  = contextA.MapType(originalType);

            ReflectionTableBuilder builderB = new ReflectionTableBuilder();

            builderB.ForType <DecoratedTypes.Base>()
            .AddTypeAttributes(new InheritedSingleAttribute("2"), new InheritedMultiAttribute("2"), new NonInheritedSingleAttribute("2"), new NonInheritedMultiAttribute("2"))
            .AddMemberAttributes(t => t.OverriddenProperty, new InheritedSingleAttribute("2"), new InheritedMultiAttribute("2"), new NonInheritedSingleAttribute("2"), new NonInheritedMultiAttribute("2"))
            ;

            var tableB   = builderB.CreateTable();
            var contextB = new TableReflectionContext(tableB, TableReflectionContextOptions.Default);

            var mappedTypeComposite = contextB.MapType(mappedTypeA);

            var actual   = FilterAttributes(mappedTypeComposite.GetCustomAttributes());
            var expected = new Attribute[]
            {
                new NonInheritedMultiAttribute(nameof(DecoratedTypes.Base)),
                new InheritedMultiAttribute(nameof(DecoratedTypes.Base)),
                new InheritedMultiAttribute("Q"),
                new NonInheritedMultiAttribute("Q"),
                new InheritedSingleAttribute("2"),
                new InheritedMultiAttribute("2"),
                new NonInheritedSingleAttribute("2"),
                new NonInheritedMultiAttribute("2")
            };

            SequenceAssert.AreEquivalent(expected, actual);

            actual   = FilterAttributes(mappedTypeComposite.GetProperty(nameof(UndecoratedTypes.Base.OverriddenProperty)).GetCustomAttributes());
            expected = new Attribute[]
            {
                new NonInheritedMultiAttribute(nameof(DecoratedTypes.Base)),
                new InheritedMultiAttribute(nameof(DecoratedTypes.Base)),
                new InheritedMultiAttribute("Q"),
                new NonInheritedMultiAttribute("Q"),
                new InheritedSingleAttribute("2"),
                new InheritedMultiAttribute("2"),
                new NonInheritedSingleAttribute("2"),
                new NonInheritedMultiAttribute("2")
            };

            SequenceAssert.AreEquivalent(expected, actual);
        }
        public void GetCustomAttributes_SpecificAttributeType_CorrectlyFiltersAttributes()
        {
            ReflectionTableBuilder builderA = new ReflectionTableBuilder();

            builderA.ForType <UndecoratedTypes.Base>()
            .AddTypeAttributes(CreateTestAttributes(nameof(UndecoratedTypes.Base)));

            var tableA   = builderA.CreateTable();
            var contextA = new TableReflectionContext(tableA, TableReflectionContextOptions.Default);

            var actual   = contextA.MapType(typeof(UndecoratedTypes.Base)).GetCustomAttributes(typeof(InheritedSingleAttribute), true);
            var expected = typeof(DecoratedTypes.Base).GetCustomAttributes(typeof(InheritedSingleAttribute), true);

            Assert.AreEqual(expected.GetType(), actual.GetType());
            SequenceAssert.AreEquivalent(expected, actual);
        }
        public void GetCustomAttributes_FieldInfo_ReturnsCorrectAttributes()
        {
            TestAll(info =>
            {
                FieldInfo[] sourceFields = info.SourceType.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                foreach (var sourceField in sourceFields)
                {
                    var targetField = info.TargetType.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                      .SingleOrDefault(field => field.Name == sourceField.Name && field.DeclaringType.Name == sourceField.DeclaringType.Name);

                    Assert.IsNotNull(targetField, $"Field {sourceField.Name} was not found in class {info.TargetType.Name}");

                    SequenceAssert.AreEquivalent(sourceField.GetCustomAttributes(false), FilterAttributes(targetField.GetCustomAttributes(false)), $"Attribute mismatch och field {sourceField.DeclaringType.Name}.{sourceField.Name} (inherit=false)");

                    object[] expectedInherited = sourceField.GetCustomAttributes(true);
                    SequenceAssert.AreEquivalent(expectedInherited, FilterAttributes(targetField.GetCustomAttributes(true)), $"Attribute mismatch och field {sourceField.DeclaringType.Name}.{sourceField.Name} (inherit=true)");
                }
            });
        }
        public void GetCustomAttributes_PropertyInfoSpecificAttribute_ReturnsCorrectAttributes()
        {
            TestAll(info =>
            {
                PropertyInfo[] sourceProperties = info.SourceType.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                foreach (var sourceProperty in sourceProperties)
                {
                    var targetProperty = info.TargetType.GetProperty(sourceProperty.Name, sourceProperty.PropertyType, sourceProperty.GetIndexParameters().Select(p => p.ParameterType).ToArray());

                    Assert.IsNotNull(targetProperty, $"Property {sourceProperty.Name} was not found in class {info.TargetType.Name}");

                    SequenceAssert.AreEquivalent(sourceProperty.GetCustomAttributes(typeof(TestAttribute), false), targetProperty.GetCustomAttributes(typeof(TestAttribute), false), $"Attribute mismatch och property {sourceProperty.DeclaringType.Name}.{sourceProperty.Name} (inherit=false)");

                    bool honorInheritance = info.ReflectionContext.Options.HasFlag(TableReflectionContextOptions.HonorPropertyAttributeInheritance);

                    // The default PropertyInfo.GetCustomAttributes ignores the inherit flag, so we need to use the Attribute.GetCustomAttributes method
                    // to get inheritance behavior. However, this method can only be used with RuntimeTypes, so we cannot use it for the target type. Instead
                    // this is controlled via the reflection context options.
                    object[] expectedInherited = honorInheritance ? Attribute.GetCustomAttributes(sourceProperty, true) : sourceProperty.GetCustomAttributes(true);
                    SequenceAssert.AreEquivalent(expectedInherited, FilterAttributes(targetProperty.GetCustomAttributes(true)), $"Attribute mismatch och property {sourceProperty.DeclaringType.Name}.{sourceProperty.Name} (inherit=true)");
                }
            });
        }