public void GenericBaseTypesForEntity()
        {
            Type           entityType       = typeof(EntityWithGenericBaseType);
            HashSet <Type> knownEntityTypes = new HashSet <Type>()
            {
                entityType
            };

            Type surrogateType = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, entityType);

            Assert.IsNotNull(surrogateType, "No surrogate type was generated.");
            Assert.AreNotEqual(entityType, surrogateType, "Surrogate type should be a different type than the actual entity type.");
            Assert.AreEqual(entityType.FullName, surrogateType.FullName, "Surrogate has an unexpected name.");
            Assert.AreEqual(typeof(object), surrogateType.BaseType, "Surrogate has an unexpected base type.");

            var additionalProperty = surrogateType.GetProperty("AdditionalProperty");

            Assert.IsNotNull(additionalProperty, "Missing AdditionalProperty property.");
            Assert.AreEqual(typeof(string), additionalProperty.PropertyType, "Unexpected property type.");

            var keyProperty = surrogateType.GetProperty("Key");

            Assert.IsNotNull(keyProperty, "Missing Key property.");
            Assert.AreEqual(typeof(int), keyProperty.PropertyType, "Unexpected property type.");
        }
        private void TestClrProperty <T>(Type entityType, Action <Type, PropertyInfo, object> verify)
        {
            string propertyName = "TestProperty";

            HashSet <Type> knownEntityTypes = new HashSet <Type>()
            {
                entityType
            };
            Type   surrogateType = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, entityType);
            object surrogateObj  = Activator.CreateInstance(surrogateType, Activator.CreateInstance(entityType));
            var    p             = surrogateType.GetProperty(propertyName);

            Assert.IsNotNull(p, "Property doesn't exist.");
            verify(surrogateType, p, surrogateObj);
        }
        public void InheritanceClrProperties()
        {
            // Actual inheritance is Hidden_Base <-- Visible_Base <-- Hidden_Derived1 <-- Hidden_Derived2 <-- Visible_Derived
            // Visible inheritance is only Visible_Base <-- Visible_Derived
            Type visibleBaseEntityType    = typeof(SurrogateTestEntity_ClrProperty_Inheritance_Visible_Base);
            Type visibleDerivedEntityType = typeof(SurrogateTestEntity_ClrProperty_Inheritance_Visible_Derived);

            // Known types exclude the intermediate Hidden_Derived1 and Hidden_Derived2 and expect its properties to lift
            // up to the first visible subclass (Visible_Derived)
            HashSet <Type> knownEntityTypes = new HashSet <Type>()
            {
                visibleBaseEntityType, visibleDerivedEntityType
            };

            Type visibleBaseSurrogateType    = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, visibleBaseEntityType);
            Type visibleDerivedSurrogateType = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, visibleDerivedEntityType);

            // The surrogate for the visible base should appear to derive from Object because its true base type is not exposed
            Assert.IsNotNull(visibleBaseSurrogateType, "No base surrogate type was generated.");
            Assert.AreNotEqual(visibleBaseEntityType, visibleBaseSurrogateType, "Base surrogate type should be a different type than the actual entity type.");
            Assert.AreEqual(visibleBaseEntityType.FullName, visibleBaseSurrogateType.FullName, "Visible base surrogate has an unexpected name.");
            Assert.AreEqual(typeof(object), visibleBaseSurrogateType.BaseType, "Visible base surrogate has an unexpected base type.");

            // The surrogate for the visible derived type should subclass the visible base.  The unexposed intermediate types are flattened.
            Assert.IsNotNull(visibleDerivedSurrogateType, "No visible derived surrogate type was generated.");
            Assert.AreNotEqual(visibleDerivedEntityType, visibleDerivedSurrogateType, "Visible derived surrogate type should be a different type than the actual entity type.");
            Assert.AreEqual(visibleDerivedEntityType.FullName, visibleDerivedSurrogateType.FullName, "Visible derived surrogate has an unexpected name.");
            Assert.AreEqual(visibleBaseSurrogateType, visibleDerivedSurrogateType.BaseType, "Visible derived surrogate has an unexpected base type.");

            // The visible base class should have its own property
            var visibleBaseProperty = visibleBaseSurrogateType.GetProperty("VisibleBaseProperty");

            Assert.IsNotNull(visibleBaseProperty, "Visible_Base type should have exposed VisibleBaseProperty");

            // The visible base should have lifted properties from its unexposed base
            var hiddenBaseProperty = visibleBaseSurrogateType.GetProperty("HiddenBaseProperty");

            Assert.IsNotNull(hiddenBaseProperty, "Visible_Derived type should have lifted HiddenBaseProperty");

            var hiddenDerived1Property = visibleDerivedSurrogateType.GetProperty("HiddenDerived1Property");

            Assert.IsNotNull(hiddenDerived1Property, "Visible_Derived should have lifted HiddenDerived1Property from unexposed base type");

            var hiddenDerived2Property = visibleDerivedSurrogateType.GetProperty("HiddenDerived2Property");

            Assert.IsNotNull(hiddenDerived2Property, "Visible_Derived should have lifted HiddenDerived2Property from unexposed base type");
        }
        public void InheritanceVirtualProperties()
        {
            // Add some TDP properties to the same logical entity hierarchy tested above in InheritanceClrProperties
            AddVirtualProperty <SurrogateTestEntity_VirtualProperty_Inheritance_Hidden_Base, string>("HiddenBaseVirtualProperty");
            AddVirtualProperty <SurrogateTestEntity_VirtualProperty_Inheritance_Visible_Base, string>("VisibleBaseVirtualProperty");
            AddVirtualProperty <SurrogateTestEntity_VirtualProperty_Inheritance_Hidden_Derived1, string>("HiddenDerived1VirtualProperty");
            AddVirtualProperty <SurrogateTestEntity_VirtualProperty_Inheritance_Hidden_Derived2, string>("HiddenDerived2VirtualProperty");
            AddVirtualProperty <SurrogateTestEntity_VirtualProperty_Inheritance_Visible_Derived, string>("VisibleDerivedVirtualProperty");

            // Actual inheritance is Hidden_Base <-- Visible_Base <-- Hidden_Derived1 <-- Hidden_Derived2 <-- Visible_Derived
            // Visible inheritance is only Visible_Base <-- Visible_Derived
            Type visibleBaseEntityType    = typeof(SurrogateTestEntity_VirtualProperty_Inheritance_Visible_Base);
            Type visibleDerivedEntityType = typeof(SurrogateTestEntity_VirtualProperty_Inheritance_Visible_Derived);

            // Known types exclude the intermediate Hidden_Derived1 and Hidden_Derived2 and expect its properties to lift
            // up to the first visible subclass (Visible_Derived)
            HashSet <Type> knownEntityTypes = new HashSet <Type>()
            {
                visibleBaseEntityType, visibleDerivedEntityType
            };

            Type visibleBaseSurrogateType    = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, visibleBaseEntityType);
            Type visibleDerivedSurrogateType = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, visibleDerivedEntityType);

            // The visible base class should have its own property
            var visibleBaseProperty = visibleBaseSurrogateType.GetProperty("VisibleBaseVirtualProperty");

            Assert.IsNotNull(visibleBaseProperty, "Visible_Base type should have exposed VisibleBaseVirtualProperty");

            // The visible base should have lifted properties from its unexposed base
            var hiddenBaseProperty = visibleBaseSurrogateType.GetProperty("HiddenBaseVirtualProperty");

            Assert.IsNotNull(hiddenBaseProperty, "Visible_Derived type should have lifted HiddenBaseVirtualProperty");

            var hiddenDerived1Property = visibleDerivedSurrogateType.GetProperty("HiddenDerived1VirtualProperty");

            Assert.IsNotNull(hiddenDerived1Property, "Visible_Derived should have lifted HiddenDerived1VirtualProperty from unexposed base type");

            var hiddenDerived2Property = visibleDerivedSurrogateType.GetProperty("HiddenDerived2VirtualProperty");

            Assert.IsNotNull(hiddenDerived2Property, "Visible_Derived should have lifted HiddenDerived2VirtualProperty from unexposed base type");
        }
        private void TestVirtualProperty <T>(Type entityType, bool isReadOnly, Action <Type, PropertyInfo, object> verify)
        {
            string propertyName = "TestProperty";
            MockTypeDescriptionProvider provider = new MockTypeDescriptionProvider(() =>
            {
                Dictionary <object, T> valueMap = new Dictionary <object, T>();

                Action <object, T> setter;
                if (isReadOnly)
                {
                    setter = null;
                }
                else
                {
                    setter = (obj, value) => valueMap[obj] = value;
                }

                return(new MockPropertyDescriptor <T>(
                           propertyName,
                           entityType,
                           getter: obj =>
                {
                    T value;
                    valueMap.TryGetValue(obj, out value);
                    return value;
                },
                           setter: setter));
            });

            TypeDescriptor.AddProvider(provider, entityType);
            HashSet <Type> knownEntityTypes = new HashSet <Type>()
            {
                entityType
            };
            Type   surrogateType = DataContractSurrogateGenerator.GetSurrogateType(knownEntityTypes, entityType);
            object surrogateObj  = Activator.CreateInstance(surrogateType, Activator.CreateInstance(entityType));
            var    p             = surrogateType.GetProperty(propertyName);

            Assert.IsNotNull(p, "Property doesn't exist.");
            verify(surrogateType, p, surrogateObj);
            TypeDescriptor.RemoveProvider(provider, entityType);
        }
        public void DataContractPropagation()
        {
            Type entityType  = typeof(MockReport);
            Type complexType = typeof(MockReportBody);

            // register TDPs
            DomainServiceDescription.GetDescription(typeof(MockCustomerDomainService));

            HashSet <Type> knownExposedTypes = new HashSet <Type>()
            {
                entityType, complexType
            };
            Type entityTypeSurrogate  = DataContractSurrogateGenerator.GetSurrogateType(knownExposedTypes, entityType);
            Type complexTypeSurrogate = DataContractSurrogateGenerator.GetSurrogateType(knownExposedTypes, complexType);

            List <string> actualTypeResult      = new List <string>();
            List <string> actualSurrogateResult = new List <string>();

            // DataContract first
            actualTypeResult.Add(GetDataContract(entityType));
            actualSurrogateResult.Add(GetDataContract(entityTypeSurrogate));

            actualTypeResult.Add(GetDataContract(complexType));
            actualSurrogateResult.Add(GetDataContract(complexTypeSurrogate));

            // DataMembers
            // Order exists on the type, but not on the surrogates.
            // We need to compare only the surrogate's Order to the expected.
            GetDataMember(entityType, false, actualTypeResult, "Customer");
            GetDataMember(entityTypeSurrogate, true, actualSurrogateResult);
            GetDataMember(complexType, false, actualTypeResult);
            GetDataMember(complexTypeSurrogate, true, actualSurrogateResult);

            Func <string, string, string> aggregate = (s1, s2) => s1 + " " + s2;
            string expected  = actualTypeResult.Aggregate(aggregate);
            string surrogate = actualSurrogateResult.Aggregate(aggregate);

            Assert.AreEqual(expected, surrogate, "Surrogate does not match expected results.");
        }