private static void SetupTestMetadata(Type entityClrType, Type[] primitiveTypes, out ResourceType entityResourceType, out ProviderMetadataSimulator workspace, out PrimitiveResourceTypeMap primitiveTypeMap)
 {
     KeyValuePair<Type, string>[] mappedPrimitiveTypes = BuildTypeMap(primitiveTypes);
     primitiveTypeMap = new PrimitiveResourceTypeMap(mappedPrimitiveTypes.ToArray());
     entityResourceType = new ResourceType(entityClrType, ResourceTypeKind.EntityType, null, entityClrType.Namespace, entityClrType.Name, false);
     workspace = new ProviderMetadataSimulator(new List<Type>() { entityClrType });
 }
 public void TestInitialize()
 {
     typeMap = GetTestPrimitiveMap();
 }
        public void ValidatePrimitiveResourceTypeMapConstructorHasAllBuiltInTypes()
        {
            PrimitiveResourceTypeMap mapping = new PrimitiveResourceTypeMap();

            string edmBinaryTypeName = "Binary";
            string edmBooleanTypeName = "Boolean";
            string edmByteTypeName = "Byte";
            string edmDateTimeOffsetName = "DateTimeOffset";
            string edmDecimalTypeName = "Decimal";
            string edmDoubleTypeName = "Double";
            string edmGuidTypeName = "Guid";
            string edmSingleTypeName = "Single";
            string edmSByteTypeName = "SByte";
            string edmInt16TypeName = "Int16";
            string edmInt32TypeName = "Int32";
            string edmInt64TypeName = "Int64";
            string edmStringTypeName = "String";
            string edmStreamTypeName = "Stream";
            string edmGeographyTypeName = "Geography";
            string edmPointTypeName = "GeographyPoint";
            string edmLineStringTypeName = "GeographyLineString";
            string edmPolygonTypeName = "GeographyPolygon";
            string edmGeographyCollectionTypeName = "GeographyCollection";
            string edmMultiLineStringTypeName = "GeographyMultiLineString";
            string edmMultiPointTypeName = "GeographyMultiPoint";
            string edmMultiPolygonTypeName = "GeographyMultiPolygon";
            string edmGeometryTypeName = "Geometry";
            string edmGeometryPointTypeName = "GeometryPoint";
            string edmGeometryLineStringTypeName = "GeometryLineString";
            string edmGeometryPolygonTypeName = "GeometryPolygon";
            string edmGeometryCollectionTypeName = "GeometryCollection";
            string edmGeometryMultiLineStringTypeName = "GeometryMultiLineString";
            string edmGeometryMultiPointTypeName = "GeometryMultiPoint";
            string edmGeometryMultiPolygonTypeName = "GeometryMultiPolygon";
            string edmDurationTypeName = "Duration";
            
            KeyValuePair<Type, string>[] expectedBuiltInTypes = 
                new KeyValuePair<Type, string>[]
                {
                    new KeyValuePair<Type, string>(typeof(string), edmStringTypeName),
                    new KeyValuePair<Type, string>(typeof(Boolean), edmBooleanTypeName),
                    new KeyValuePair<Type, string>(typeof(Boolean?), edmBooleanTypeName),
                    new KeyValuePair<Type, string>(typeof(Byte), edmByteTypeName),
                    new KeyValuePair<Type, string>(typeof(Byte?), edmByteTypeName),
                    new KeyValuePair<Type, string>(typeof(DateTime), edmDateTimeOffsetName),
                    new KeyValuePair<Type, string>(typeof(DateTime?), edmDateTimeOffsetName),
                    new KeyValuePair<Type, string>(typeof(DateTimeOffset), edmDateTimeOffsetName),
                    new KeyValuePair<Type, string>(typeof(DateTimeOffset?), edmDateTimeOffsetName),
                    new KeyValuePair<Type, string>(typeof(Decimal), edmDecimalTypeName),
                    new KeyValuePair<Type, string>(typeof(Decimal?), edmDecimalTypeName),
                    new KeyValuePair<Type, string>(typeof(Double), edmDoubleTypeName),
                    new KeyValuePair<Type, string>(typeof(Double?), edmDoubleTypeName),
                    new KeyValuePair<Type, string>(typeof(Guid), edmGuidTypeName),
                    new KeyValuePair<Type, string>(typeof(Guid?), edmGuidTypeName),
                    new KeyValuePair<Type, string>(typeof(Int16), edmInt16TypeName),
                    new KeyValuePair<Type, string>(typeof(Int16?), edmInt16TypeName),
                    new KeyValuePair<Type, string>(typeof(Int32), edmInt32TypeName),
                    new KeyValuePair<Type, string>(typeof(Int32?), edmInt32TypeName),
                    new KeyValuePair<Type, string>(typeof(Int64), edmInt64TypeName),
                    new KeyValuePair<Type, string>(typeof(Int64?), edmInt64TypeName),
                    new KeyValuePair<Type, string>(typeof(SByte), edmSByteTypeName),
                    new KeyValuePair<Type, string>(typeof(SByte?), edmSByteTypeName),
                    new KeyValuePair<Type, string>(typeof(Single), edmSingleTypeName),
                    new KeyValuePair<Type, string>(typeof(Single?), edmSingleTypeName),
                    new KeyValuePair<Type, string>(typeof(byte[]), edmBinaryTypeName),
                    new KeyValuePair<Type, string>(typeof(Stream), edmStreamTypeName),
                    new KeyValuePair<Type, string>(typeof(TimeSpan), edmDurationTypeName),
                    new KeyValuePair<Type, string>(typeof(TimeSpan?), edmDurationTypeName),
                    new KeyValuePair<Type, string>(typeof(Geography), edmGeographyTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyPoint), edmPointTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyLineString), edmLineStringTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyPolygon), edmPolygonTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyCollection), edmGeographyCollectionTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyMultiPoint), edmMultiPointTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyMultiLineString), edmMultiLineStringTypeName),
                    new KeyValuePair<Type, string>(typeof(GeographyMultiPolygon), edmMultiPolygonTypeName),
                    new KeyValuePair<Type, string>(typeof(Geometry), edmGeometryTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryPoint), edmGeometryPointTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryLineString), edmGeometryLineStringTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryPolygon), edmGeometryPolygonTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryCollection), edmGeometryCollectionTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryMultiPoint), edmGeometryMultiPointTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryMultiLineString), edmGeometryMultiLineStringTypeName),
                    new KeyValuePair<Type, string>(typeof(GeometryMultiPolygon), edmGeometryMultiPolygonTypeName),
                    new KeyValuePair<Type, string>(typeof(XElement), edmStringTypeName),
                    new KeyValuePair<Type, string>(typeof(Binary), edmBinaryTypeName),
                };

            Assert.AreEqual(expectedBuiltInTypes.Length, mapping.AllPrimitives.Length, "AllPrimitives contains a different number of types than expected for the mapping provided by the default constructor.");
 
            foreach (KeyValuePair<Type, string> expectedType in expectedBuiltInTypes)
            {
                ResourceType resourceType = mapping.GetPrimitive(expectedType.Key);
                PrimitiveResourceTypeMapTests.VerifyPrimitiveResourceType(resourceType, expectedType.Key, expectedType.Value);
            }
        }
        /// <summary>
        /// Populates the member metadata for the given type
        /// </summary>
        /// <param name="resourceTypeCacheItem">Instance of ResourceTypeCacheItem containing the ResourceType and its metadata.</param>
        /// <param name="workspace">workspace containing the metadata information</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="primitiveResourceTypeMap">Map of primitive types to use when building member metadata.</param>
        internal static void PopulateMemberMetadata(
            ResourceTypeCacheItem resourceTypeCacheItem,
            IProviderMetadata workspace,
            ProviderMetadataCacheItem metadataCacheItem,
            PrimitiveResourceTypeMap primitiveResourceTypeMap)
        {
            Debug.Assert(resourceTypeCacheItem != null, "resourceTypeCacheItem != null");
            Debug.Assert(workspace != null, "workspace != null");

            var resourceType = resourceTypeCacheItem.ResourceType;

            // Find the type from the OSpace
            IProviderType edmType = workspace.GetProviderType(resourceType.FullName);
            foreach (IProviderMember member in edmType.Members)
            {
                ResourcePropertyKind kind = (ResourcePropertyKind)(-1);

                // ObjectContextServiceProvider fails with NullReferenceException when an entity property is not public.
                // If the property on the CLR type which is representing the EDM type has non-public properties but those properties are part of the
                // conceptual model, the server will try to load CLR metadata for these properties.
                // The Type.GetProperty(propertyName) method used BindingFlags.Instance | BindingFlags.Public by default if no binding flags are specified.
                // Since the property was not found with these binding flags, the GetProperty method returns null, which we didn't check for in v1 and v2 and threw an NRE.
                // We now check for null return values from this function and throw if we find that the model property declared on the CLR type is not public.
                PropertyInfo propertyInfo = resourceType.InstanceType.GetProperty(member.Name, BindingFlags.Instance | BindingFlags.Public);
                if (propertyInfo == null)
                {
                    throw new DataServiceException((int)HttpStatusCode.InternalServerError, Strings.ObjectContext_PublicPropertyNotDefinedOnType(edmType.Name, member.Name));
                }

                ResourceType propertyType = null;
                switch (member.EdmTypeKind)
                {
                    case BuiltInTypeKind.PrimitiveType:
#if !INTERNAL_DROP && !EFRTM
                        Type propertyClrType = ObjectContextSpatialUtil.IsDbGeography(propertyInfo.PropertyType) ? typeof(Geography) : propertyInfo.PropertyType;
#else
                        Type propertyClrType = propertyInfo.PropertyType;
#endif
                        propertyType = primitiveResourceTypeMap.GetPrimitive(propertyClrType);

                        if (propertyType == null)
                        {
                            throw new NotSupportedException(Strings.ObjectContext_PrimitiveTypeNotSupported(member.Name, edmType.Name, member.EdmTypeName));
                        }

                        if (member.IsKey)
                        {
                            kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                        }
                        else
                        {
                            kind = ResourcePropertyKind.Primitive;
                        }

                        break;
                    case BuiltInTypeKind.ComplexType:
                        kind = ResourcePropertyKind.ComplexType;
                        propertyType = metadataCacheItem.TryGetResourceType(propertyInfo.PropertyType);
                        break;
                    case BuiltInTypeKind.EntityType:
                        kind = ResourcePropertyKind.ResourceReference;
                        propertyType = metadataCacheItem.TryGetResourceType(propertyInfo.PropertyType);
                        break;
                    case BuiltInTypeKind.CollectionType:
                        kind = ResourcePropertyKind.ResourceSetReference;
                        Type collectionItemClrType = workspace.GetClrType(member.CollectionItemType);
                        Debug.Assert(!WebUtil.IsPrimitiveType(collectionItemClrType), "We don't support collections of primitives, we shouldn't see one here");
                        propertyType = metadataCacheItem.TryGetResourceType(collectionItemClrType);
                        break;
                    default:
                        throw new NotSupportedException(Strings.ObjectContext_PrimitiveTypeNotSupported(member.Name, edmType.Name, member.EdmTypeName));
                }

                Debug.Assert(propertyType != null, "propertyType != null");
                ResourceProperty resourceProperty = new ResourceProperty(propertyInfo.Name, kind, propertyType);
                SetMimeTypeForMappedMember(resourceProperty, member);
                resourceType.AddProperty(resourceProperty);
#if !EF6Provider
                ObjectContextServiceProvider.PopulateFacets(resourceProperty, member.Facets, resourceProperty.ResourceType.ResourceTypeKind == ResourceTypeKind.EntityType /*ignoreNullableAnnotation*/);
                ObjectContextServiceProvider.PopulateAnnotations(member.MetadataProperties, resourceProperty.AddCustomAnnotation);
#endif
                resourceTypeCacheItem.AddResourcePropertyCacheItem(resourceProperty, new ObjectContextResourcePropertyCacheItem(propertyInfo, member));
            }
        }