/// <summary>
 /// Visits a property
 /// </summary>
 /// <param name="payloadElement">The property to visit</param>
 /// <param name="value">The value of the property</param>
 protected override void VisitProperty(PropertyInstance payloadElement, ODataPayloadElement value)
 {
     this.VisitProperty(payloadElement, value, null);
 }
            private void VisitProperty(PropertyInstance payloadElement, ODataPayloadElement value, Action action)
            {
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

                try
                {
                    var currentType = this.typeStack.Peek();
                    ExceptionUtilities.CheckObjectNotNull(currentType, "Current type should not be null");

                    var propertyInfo = currentType.GetProperty(payloadElement.Name);
                    ExceptionUtilities.CheckObjectNotNull(propertyInfo, "Could not find property '{0}' on type '{1}'", payloadElement.Name, currentType);

                    var genericCollectionType = propertyInfo.PropertyType.GetInterfaces().Where(t => t.IsGenericType()).SingleOrDefault(t => typeof(ICollection<>) == t.GetGenericTypeDefinition());
                    if (genericCollectionType != null)
                    {
                        this.typeStack.Push(genericCollectionType.GetGenericArguments()[0]);
                    }
                    else
                    {
                        this.typeStack.Push(propertyInfo.PropertyType);
                    }

                    base.VisitProperty(payloadElement, value);

                    if (action != null)
                    {
                        action();
                    }
                }
                finally
                {
                    this.typeStack.Pop();
                }
            }
Ejemplo n.º 3
0
 /// <summary>
 /// Replace the old property with a new property
 /// </summary>
 /// <param name="oldInstance">The old property to be replaced</param>
 /// <param name="newInstance">The property to replace the old one</param>
 public void Replace(PropertyInstance oldInstance, PropertyInstance newInstance)
 {
     this.properties[this.properties.IndexOf(oldInstance)] = newInstance;
 }
Ejemplo n.º 4
0
        public void ComplexValueWithMetadataTest()
        {
            // Use some standard complex value payloads first
            IEnumerable<PayloadReaderTestDescriptor> testDescriptors = PayloadReaderTestDescriptorGenerator.CreateComplexValueTestDescriptors(this.Settings, true);

            // Add metadata validation tests
            EdmModel model = new EdmModel();
            var innerComplexType = model.ComplexType("InnerComplexType");
            innerComplexType.AddStructuralProperty("name", EdmCoreModel.Instance.GetString(true));

            var complexType = model.ComplexType("ComplexType");
            complexType.AddStructuralProperty("number", EdmPrimitiveTypeKind.Int32);
            complexType.AddStructuralProperty("string", EdmCoreModel.Instance.GetString(true));
            complexType.AddStructuralProperty("complex", MetadataUtils.ToTypeReference(innerComplexType, true));

            var entityType = model.EntityType("EntityType");
            entityType.KeyProperty("Id", EdmCoreModel.Instance.GetInt32(false));
            model.Fixup();

            // Test that different types of properties not present in the metadata all fail
            IEnumerable<PropertyInstance> undeclaredPropertyTestCases = new PropertyInstance[]
            {
                PayloadBuilder.PrimitiveProperty("undeclared", 42),
                PayloadBuilder.Property("undeclared", PayloadBuilder.ComplexValue(innerComplexType.FullName())),
                PayloadBuilder.Property("undeclared", PayloadBuilder.PrimitiveMultiValue(EntityModelUtils.GetCollectionTypeName("Edm.Int32"))),
                PayloadBuilder.Property("undeclared", PayloadBuilder.ComplexMultiValue(EntityModelUtils.GetCollectionTypeName("TestModel.InnerComplexType"))),
            };

            testDescriptors = testDescriptors.Concat(
                undeclaredPropertyTestCases.Select(tc =>
                {
                    return new PayloadReaderTestDescriptor(this.Settings)
                    {
                        PayloadElement = PayloadBuilder.ComplexValue(complexType.FullName()).WithTypeAnnotation(complexType)
                            .Property(tc),
                        PayloadEdmModel = model,
                        ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", "undeclared", "TestModel.ComplexType"),
                    };
                }));

            testDescriptors = testDescriptors.Concat(new[]
            {
                // Property which should take typename not from value but from the parent metadata
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.ComplexValue(complexType.FullName()).WithTypeAnnotation(complexType)
                        .Property("complex", PayloadBuilder.ComplexValue(innerComplexType.FullName()).PrimitiveProperty("name", null)
                            .JsonRepresentation("{ \"name\" : null }").XmlRepresentation("<d:name m:null=\"true\" />")
                            .AddAnnotation(new SerializationTypeNameTestAnnotation() { TypeName = null })),
                    PayloadEdmModel = model,
                },
                // Property which is declared in the metadata but with a different type
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.ComplexValue(complexType.FullName()).WithTypeAnnotation(complexType)
                        .Property("complex", PayloadBuilder.ComplexValue(complexType.FullName())),
                    PayloadEdmModel = model,
                    ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_IncompatibleType", "TestModel.ComplexType", "TestModel.InnerComplexType"),
                },
                // Property which is declared in the metadata but with a wrong kind
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.ComplexValue(complexType.FullName()).WithTypeAnnotation(complexType)
                        .Property("complex", PayloadBuilder.ComplexValue(entityType.FullName())),
                    PayloadEdmModel = model,
                    ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_IncorrectTypeKind", "TestModel.EntityType", "Complex", "Entity"),
                },
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.ComplexValue("").WithTypeAnnotation(complexType),
                    PayloadEdmModel = model,
                    ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_UnrecognizedTypeName", string.Empty)
                },
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.ComplexValue("TestModel.NonExistant").WithTypeAnnotation(complexType),
                    PayloadEdmModel = model,
                    ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_UnrecognizedTypeName", "TestModel.NonExistant"),
                },
            });

            // Wrap the complex type in a property
            testDescriptors = testDescriptors
                .Select((td, index) => new PayloadReaderTestDescriptor(td) { PayloadDescriptor = td.PayloadDescriptor.InProperty("propertyName" + index)})
                .SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td));

            // Handcrafted cases
            testDescriptors = testDescriptors.Concat(new[]
            {
                // Top-level complex property without expected type
                new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.Property("property", PayloadBuilder.ComplexValue(complexType.FullName()).PrimitiveProperty("number", 42)),
                    PayloadEdmModel = model
                },
            });

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors,
                this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations,
                (testDescriptor, testConfiguration) =>
                {
                    var property = testDescriptor.PayloadElement as PropertyInstance;
                    if (property != null && testConfiguration.Format == ODataFormat.Atom)
                    {
                        property.Name = null;
                    }
                    testDescriptor.RunTest(testConfiguration);
                });
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Adds the given property to the complex instance, and sets it as the property's parent
 /// </summary>
 /// <param name="toAdd">The property to add</param>
 public void Add(PropertyInstance toAdd)
 {
     this.properties.Add(toAdd);
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Removes the given property, if present, and sets it's parent to null
 /// </summary>
 /// <param name="toRemove">The property to remove</param>
 public void Remove(PropertyInstance toRemove)
 {
     this.properties.Remove(toRemove);
 }
        /// <summary>
        /// Helper method for visiting null or empty properties
        /// </summary>
        /// <param name="payloadElement">The property to visit</param>
        protected override void VisitEmptyOrNullProperty(PropertyInstance payloadElement)
        {
            base.VisitEmptyOrNullProperty(payloadElement);

            var property = this.MetadataStack.Peek() as MemberProperty;
            var navigation = this.MetadataStack.Peek() as NavigationProperty;

            if (property != null)
            {
                ExceptionUtilities.Assert(payloadElement.Name == property.Name, "Property name mismatch");
                payloadElement.AddAnnotationIfNotExist(new MemberPropertyAnnotation() { Property = property });
            }
            else
            {
                ExceptionUtilities.CheckObjectNotNull(navigation, "Expected property or navigation, got '{0}'", this.MetadataStack.Peek());
                ExceptionUtilities.Assert(payloadElement.Name == navigation.Name, "Property name mismatch");
                payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation() { Property = navigation });

                var emptyCollection = payloadElement as EmptyCollectionProperty;
                if (emptyCollection != null && emptyCollection.Value != null)
                {
                    emptyCollection.Value.AddAnnotationIfNotExist(new EntitySetAnnotation() { EntitySet = this.CurrentEntitySet.GetRelatedEntitySet(navigation) });
                }
            }
        }
Ejemplo n.º 8
0
        public void UndeclaredClosedPropertyTest()
        {
            EdmModel model = new EdmModel();
            var entityType = new EdmEntityType("TestModel", "ClosedEntityType");
            entityType.AddKeys(entityType.AddStructuralProperty("ID", EdmCoreModel.Instance.GetInt32(false)));
            model.AddElement(entityType);
            var complexType = new EdmComplexType("TestModel", "DeclaredComplexType");
            complexType.AddStructuralProperty("foo", EdmCoreModel.Instance.GetString(true));
            model.AddElement(complexType);
            var container = new EdmEntityContainer("TestModel", "DefaultContainer");
            container.AddEntitySet("ClosedEntitySet", entityType);
            model.AddElement(container);

            string propertyName = "UndeclaredProperty";

            // Test various types of properties, all of which are undeclared in metadata.
            IEnumerable<PropertyInstance> testCases = new PropertyInstance[]
            {
                // Primitive property
                PayloadBuilder.PrimitiveProperty(propertyName, 15),
                // Complex property
                PayloadBuilder.Property(propertyName, 
                    PayloadBuilder.ComplexValue("TestModel.DeclaredComplexType").PrimitiveProperty("foo", "bar")),
                // Stream property
                PayloadBuilder.StreamProperty(propertyName, "http://odata.org/readlink"),
                // Collection property (over primitive type)
                PayloadBuilder.Property(propertyName, 
                    PayloadBuilder.PrimitiveMultiValue(EntityModelUtils.GetCollectionTypeName("Edm.Boolean"))),
                // Collection property (over declared complex type)
                PayloadBuilder.Property(propertyName, 
                    PayloadBuilder.ComplexMultiValue(EntityModelUtils.GetCollectionTypeName("TestModel.DeclaredComplexType"))),
                // Collection property (over undeclared complex type)
                PayloadBuilder.Property(propertyName, 
                    PayloadBuilder.ComplexMultiValue(EntityModelUtils.GetCollectionTypeName("TestModel.UndeclaredComplexType"))),
                // Navigation property
                PayloadBuilder.NavigationProperty(propertyName, "http://odata.org/navlink"),
            };

            IEnumerable<PayloadReaderTestDescriptor> testDescriptors = testCases.Select(testCase =>
            {
                return new PayloadReaderTestDescriptor(this.Settings)
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.ClosedEntityType")
                        .PrimitiveProperty("ID", 42)
                        .Property(testCase),
                    PayloadEdmModel = model,
                    ExpectedResultCallback =
                        (tc) => new PayloadReaderTestExpectedResult(this.Settings.ExpectedResultSettings)
                        {
                            ExpectedException = (tc.Format == ODataFormat.Json && testCase is NavigationPropertyInstance)
                                ? tc.IsRequest
                                    ? ODataExpectedExceptions.ODataException("ODataJsonLightEntryAndFeedDeserializer_PropertyWithoutValueWithUnknownType", propertyName)
                                    : ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", propertyName, "TestModel.ClosedEntityType")
                                : ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", propertyName, "TestModel.ClosedEntityType"),
                        },
                    SkipTestConfiguration = tc => testCase is NamedStreamInstance && tc.IsRequest
                };
            });

            testDescriptors = testDescriptors.SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors,
                this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations,
                (testDescriptor, testConfiguration) =>
                {
                    testDescriptor.RunTest(testConfiguration);
                });
        }
Ejemplo n.º 9
0
        private bool ShouldReplaceWithCollection(PropertyInstance property, bool isNull, string collectionTypeName)
        {
            ExceptionUtilities.CheckArgumentNotNull(property, "property");

            // only replace root elements with no null-marker or type name
            bool shouldReplace = this.isRoot && !isNull && collectionTypeName == null;

            // only replace if it is from a service operation which returns a collection of complex or primitive types
            if (shouldReplace)
            {
                var functionAnnotation = property.Annotations.OfType<FunctionAnnotation>().SingleOrDefault();
                if (functionAnnotation != null)
                {
                    var dataTypeAnnotation = property.Annotations.OfType<DataTypeAnnotation>().SingleOrDefault();
                    if (dataTypeAnnotation != null)
                    {
                        ExceptionUtilities.CheckObjectNotNull(dataTypeAnnotation.DataType, "DataType Annotation doesn't contain a DataType");

                        var collectionType = dataTypeAnnotation.DataType as CollectionDataType;
                        if (collectionType != null)
                        {
                            return collectionType.ElementDataType is ComplexDataType || collectionType.ElementDataType is PrimitiveDataType;
                        }
                    }
                }
            }
            
            return false;
        }
        /// <summary>
        /// Helper method for visiting properties
        /// </summary>
        /// <param name="payloadElement">The property to visit</param>
        /// <param name="value">The value of the property</param>
        protected override void VisitProperty(PropertyInstance payloadElement, ODataPayloadElement value)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var property = this.MetadataStack.Peek() as MemberProperty;
            if (property != null)
            {
                ExceptionUtilities.Assert(payloadElement.Name == property.Name, "Property name mismatch");
                payloadElement.AddAnnotationIfNotExist(new MemberPropertyAnnotation() { Property = property });

                try
                {
                    this.MetadataStack.Push(property.PropertyType);
                    base.VisitProperty(payloadElement, value);
                }
                finally
                {
                    this.MetadataStack.Pop();
                }
            }
            else
            {
                var navprop = this.MetadataStack.Peek() as NavigationProperty;
                if (navprop != null)
                {
                    ExceptionUtilities.Assert(payloadElement.Name == navprop.Name, "Property name mismatch");
                    try
                    {
                        this.MetadataStack.Push(this.CurrentEntitySet.GetRelatedEntitySet(navprop));
                        base.VisitProperty(payloadElement, value);
                    }
                    finally
                    {
                        this.MetadataStack.Pop();
                    }
                }
                else
                {
                    var serviceOperation = this.MetadataStack.OfType<Function>().SingleOrDefault(f => f.Name.Equals(payloadElement.Name, StringComparison.Ordinal));
                    if (payloadElement.Name.Contains('.'))
                    {
                        // if the action has a name collision with a property in the entity, it will have the <container name>.<action name> in the payload
                        // split the payloadElement.Name and get the last token which will match the function name
                        string lastToken = payloadElement.Name.Split('.').Last();
                        serviceOperation = this.MetadataStack.OfType<Function>().SingleOrDefault(f => f.Name.Equals(lastToken, StringComparison.Ordinal));
                    }

                    ExceptionUtilities.CheckObjectNotNull(serviceOperation, "Expected property, got " + this.MetadataStack.Peek().ToString());

                    // Non-entity values returned from a service operation call appear identical to member properties,
                    // with the operation name as the property name
                    base.VisitProperty(payloadElement, value);
                }
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Creates a set of interesting entity instances along with metadata.
        /// </summary>
        /// <param name="settings">The test descriptor settings to use.</param>
        /// <param name="model">If non-null, the method creates complex types for the complex values and adds them to the model.</param>
        /// <param name="withTypeNames">true if the payloads should specify type names.</param>
        /// <returns>List of test descriptors with interesting entity instances as payload.</returns>
        public static IEnumerable<PayloadTestDescriptor> CreateEntityInstanceTestDescriptors(
            EdmModel model,
            bool withTypeNames)
        {
            IEnumerable<PrimitiveValue> primitiveValues = TestValues.CreatePrimitiveValuesWithMetadata(fullSet: false);
            IEnumerable<ComplexInstance> complexValues = TestValues.CreateComplexValues(model, withTypeNames, fullSet: false);
            IEnumerable<NamedStreamInstance> streamReferenceValues = TestValues.CreateStreamReferenceValues(fullSet: false);
            IEnumerable<PrimitiveMultiValue> primitiveMultiValues = TestValues.CreatePrimitiveCollections(withTypeNames, fullSet: false);
            IEnumerable<ComplexMultiValue> complexMultiValues = TestValues.CreateComplexCollections(model, withTypeNames, fullSet: false);
            IEnumerable<NavigationPropertyInstance> navigationProperties = TestValues.CreateDeferredNavigationLinks();

            // NOTE we have to copy the EntityModelTypeAnnotation on the primitive value to the NullPropertyInstance for null values since the 
            //      NullPropertyInstance does not expose a value. We will later copy it back to the value we generate for the null property.
            IEnumerable<PropertyInstance> primitiveProperties =
                primitiveValues.Select((pv, ix) => PayloadBuilder.Property("PrimitiveProperty" + ix, pv).CopyAnnotation<PropertyInstance, EntityModelTypeAnnotation>(pv));
            IEnumerable<PropertyInstance> complexProperties = complexValues.Select((cv, ix) => PayloadBuilder.Property("ComplexProperty" + ix, cv));
            IEnumerable<PropertyInstance> primitiveMultiValueProperties = primitiveMultiValues.Select((pmv, ix) => PayloadBuilder.Property("PrimitiveMultiValueProperty" + ix, pmv));
            IEnumerable<PropertyInstance> complexMultiValueProperties = complexMultiValues.Select((cmv, ix) => PayloadBuilder.Property("ComplexMultiValueProperty" + ix, cmv));

            PropertyInstance[][] propertyMatrix = new PropertyInstance[6][];
            propertyMatrix[0] = primitiveProperties.ToArray();
            propertyMatrix[1] = complexProperties.ToArray();
            propertyMatrix[2] = streamReferenceValues.ToArray();
            propertyMatrix[3] = primitiveMultiValueProperties.ToArray();
            propertyMatrix[4] = complexMultiValueProperties.ToArray();
            propertyMatrix[5] = navigationProperties.ToArray();

            IEnumerable<PropertyInstance[]> propertyCombinations = propertyMatrix.ColumnCombinations(0, 1, 6);

            int count = 0;
            foreach (PropertyInstance[] propertyCombination in propertyCombinations)
            {
                // build the entity type, add it to the model
                EdmEntityType generatedEntityType = null;
                string typeName = "PGEntityType" + count;
                EdmEntityContainer container = null;
                EdmEntitySet entitySet = null;
                if (model != null)
                {
                    // generate a new type with the auto-generated name, check that no type with this name exists and add the default key property to it.
                    Debug.Assert(model.FindDeclaredType(typeName) == null, "Entity type '" + typeName + "' already exists.");
                    generatedEntityType = new EdmEntityType("TestModel", typeName);
                    generatedEntityType.AddKeys(generatedEntityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
                    model.AddElement(generatedEntityType);
                    container = model.EntityContainer as EdmEntityContainer;

                    if (container == null)
                    {
                        container = new EdmEntityContainer("TestModel", "DefaultNamespace");
                        model.AddElement(container);
                    }

                    entitySet = container.AddEntitySet(typeName, generatedEntityType);
                }

                EntityInstance entityInstance = PayloadBuilder.Entity("TestModel." + typeName)
                    .Property("Id", PayloadBuilder.PrimitiveValue(count).WithTypeAnnotation(EdmCoreModel.Instance.GetInt32(false)));

                for (int i = 0; i < propertyCombination.Length; ++i)
                {
                    PropertyInstance currentProperty = propertyCombination[i];
                    entityInstance.Add(currentProperty);

                    if (model != null)
                    {
                        if (entitySet == null)
                        {
                            entitySet = container.FindEntitySet(typeName) as EdmEntitySet;
                        }

                        switch (currentProperty.ElementType)
                        {
                            case ODataPayloadElementType.ComplexProperty:
                                ComplexProperty complexProperty = (ComplexProperty)currentProperty;
                                generatedEntityType.AddStructuralProperty(complexProperty.Name,
                                    complexProperty.Value.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType);
                                break;

                            case ODataPayloadElementType.PrimitiveProperty:
                                PrimitiveProperty primitiveProperty = (PrimitiveProperty)currentProperty;
                                if (primitiveProperty.Value == null)
                                {
                                    generatedEntityType.AddStructuralProperty(
                                       primitiveProperty.Name,
                                       PayloadBuilder.PrimitiveValueType(null));
                                }
                                else
                                {
                                    generatedEntityType.AddStructuralProperty(primitiveProperty.Name,
                                        primitiveProperty.Value.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType);
                                }
                                break;
                            case ODataPayloadElementType.NamedStreamInstance:
                                NamedStreamInstance streamProperty = (NamedStreamInstance)currentProperty;
                                generatedEntityType.AddStructuralProperty(streamProperty.Name, EdmPrimitiveTypeKind.Stream);
                                break;

                            case ODataPayloadElementType.EmptyCollectionProperty:
                                throw new NotImplementedException();

                            case ODataPayloadElementType.NavigationPropertyInstance:
                                NavigationPropertyInstance navigationProperty = (NavigationPropertyInstance)currentProperty;
                                var navProperty = generatedEntityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo()
                                {
                                    ContainsTarget = false,
                                    Name = navigationProperty.Name,
                                    Target = generatedEntityType,
                                    TargetMultiplicity = EdmMultiplicity.One
                                });
                                entitySet.AddNavigationTarget(navProperty, entitySet);
                                break;

                            case ODataPayloadElementType.ComplexMultiValueProperty:
                                ComplexMultiValueProperty complexMultiValueProperty = (ComplexMultiValueProperty)currentProperty;
                                generatedEntityType.AddStructuralProperty(complexMultiValueProperty.Name,
                                    complexMultiValueProperty.Value.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType);
                                break;

                            case ODataPayloadElementType.PrimitiveMultiValueProperty:
                                PrimitiveMultiValueProperty primitiveMultiValueProperty = (PrimitiveMultiValueProperty)currentProperty;
                                generatedEntityType.AddStructuralProperty(primitiveMultiValueProperty.Name,
                                     primitiveMultiValueProperty.Value.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType);
                                break;

                            default:
                                throw new NotSupportedException("Unsupported element type found : " + propertyCombination[i].ElementType);
                        }
                    }
                }

                if (generatedEntityType != null)
                {
                    entityInstance.AddAnnotation(new EntityModelTypeAnnotation(generatedEntityType.ToTypeReference(true)));
                }

                yield return new PayloadTestDescriptor() { PayloadElement = entityInstance, PayloadEdmModel = model };

                count++;
            }
        }
        /// <summary>
        /// Adds a JSON-L odata.type property annotation to any properties of an open type that are
        /// not defined by the entity type.
        /// </summary>
        /// <param name="property">The property to annotate.</param>
        /// <param name="propertyValue">The property's value.</param>
        private void AnnotateIfOpenProperty(PropertyInstance property, ITypedValue propertyValue)
        {
            string propertyTypeName = propertyValue.FullTypeName;
            if (this.payloadElementStack.Count > 1 && !string.IsNullOrEmpty(propertyTypeName))
            {
                var parentEntity = this.payloadElementStack.Skip(1).First() as EntityInstance;
                if (parentEntity != null)
                {
                    if (this.testDescriptor.PayloadEdmModel != null)
                    {
                        var parentType = this.testDescriptor.PayloadEdmModel.EntityTypes().SingleOrDefault(t => t.TestFullName() == parentEntity.FullTypeName);
                        if (parentType != null &&
                        parentType.IsOpen &&
                        parentType.Properties().All(p => p.Name != property.Name) &&
                        property.Annotations.OfType<JsonLightPropertyAnnotationAnnotation>().All(a => a.AnnotationName != JsonLightConstants.ODataTypeAnnotationName))
                        {
                            property.WithPropertyAnnotation(JsonLightConstants.ODataTypeAnnotationName, propertyTypeName);
                        }
                    }

                }
            }
        }
        /// <summary>
        /// Adds or modifies a property's ExpectedTypeODataPayloadElementAnnotation, to aid generation of the context uri.
        /// </summary>
        /// <param name="property">The property to annotate.</param>
        /// <param name="propertyValueType">The type of the property's value.</param>
        /// <param name="matchesProperty">Delegate for matching the property instance to a MemberProperty.</param>
        /// <remarks>
        /// If the method cannot resolve the parent type of the property, one will be created and added to the test descriptor's 
        /// PayloadModel. The descriptor's cached model will be reset.
        /// </remarks>
        private void AddExpectedTypeToProperty(PropertyInstance property, IEdmTypeReference propertyValueType, Func<IEdmProperty, bool> matchesProperty)
        {
            if (property.Annotations.OfType<JsonLightContextUriAnnotation>().Any())
            {
                return;
            }

            var typeAnnotation = property.Annotations.OfType<ExpectedTypeODataPayloadElementAnnotation>().SingleOrDefault();
            if (typeAnnotation == null || (typeAnnotation.MemberProperty == null && string.IsNullOrEmpty(typeAnnotation.OpenMemberPropertyName)))
            {
                ExpectedTypeODataPayloadElementAnnotation annotation = typeAnnotation ?? new ExpectedTypeODataPayloadElementAnnotation();

                IEdmModel model = this.testDescriptor.PayloadEdmModel;

                var entityType = model.EntityTypes().SingleOrDefault(t => t.Properties().Any(matchesProperty));
                if (entityType != null)
                {

                    annotation.EdmEntitySet = FindEntitySet(model, entityType);
                    annotation.EdmOwningType = entityType;
                    annotation.EdmProperty = entityType.Properties().FirstOrDefault(matchesProperty);
                }
                else
                {
                    var complexType = model.SchemaElements.OfType<IEdmComplexType>().SingleOrDefault(t => t.Properties().Any(matchesProperty));
                    if (complexType != null)
                    {
                        var complexProperty = complexType.Properties().Single(p => p.Name == property.Name);

                        annotation.EdmOwningType = complexType;
                        annotation.EdmProperty = complexProperty;
                        annotation.EdmExpectedType = complexProperty.Type;
                    }
                    else
                    {
                        // Add new entity type to the model and use that
                        IEdmTypeReference propertyType = annotation.EdmExpectedType ?? propertyValueType;
                        
                        EdmEntityType newEntityType = model.FindDeclaredType("TestModel.NewType") as EdmEntityType;
                        IEdmEntitySet newEntitySet = null;
                        IEdmProperty newProperty = null;
                        string newPorpertyName = property.Name ?? propertyType.FullName() ?? "EmptyName";

                        if (newEntityType == null)
                        {
                            newEntityType = new EdmEntityType("TestModel", "NewType");
                            newProperty = newEntityType.AddStructuralProperty(newPorpertyName, propertyType);
                            ((EdmModel)model).AddElement(newEntityType);
                            var container = model.EntityContainersAcrossModels().Single() as EdmEntityContainer;
                            newEntitySet = container.AddEntitySet("NewTypes", newEntityType);
                        }
                        else
                        {
                            newProperty = newEntityType.AddStructuralProperty(newPorpertyName, propertyType);
                            newEntitySet = FindEntitySet(model, newEntityType);
                        }

                        annotation.EdmEntitySet = newEntitySet;
                        annotation.EdmOwningType = newEntityType;
                        annotation.EdmProperty = newProperty;
                        annotation.EdmExpectedType = propertyType;

                        this.testDescriptor.PayloadEdmModel = model;
                        this.testDescriptor.ResetCachedModel();
                    }
                }

                property.SetAnnotation(annotation);
            }
        }
 /// <summary>
 /// Normalizes the name of a property instance (JSON Light reports an empty name for top-level properties in requests).
 /// </summary>
 /// <param name="payloadElement">The property instance to normalize the name for.</param>
 private void NormalizePropertyName(PropertyInstance payloadElement)
 {
     if (this.IsRootElement(payloadElement))
     { 
         // NOTE: in JSON Light we report null property names.
         payloadElement.Name = null;
     }
 }
 /// <summary>
 /// Helper method for visiting properties
 /// </summary>
 /// <param name="payloadElement">The property to visit</param>
 /// <param name="value">The value of the property</param>
 protected override void VisitProperty(PropertyInstance payloadElement, ODataPayloadElement value)
 {
     using (new DelegateBasedDisposable(() => this.currentPath.Pop()))
     {
         this.currentPath.Push(payloadElement.Name);
         base.VisitProperty(payloadElement, value);
     }
 }