/// <summary>
        /// Creates the <see cref="ODataEntry"/> to be written while writing this entity.
        /// </summary>
        /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The created <see cref="ODataEntry"/>.</returns>
        public virtual ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
        {
            if (selectExpandNode == null)
            {
                throw Error.ArgumentNull("selectExpandNode");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            string typeName = entityInstanceContext.EntityType.FullName();

            ODataEntry entry = new ODataEntry
            {
                TypeName = typeName,
                Properties = CreateStructuralPropertyBag(selectExpandNode.SelectedStructuralProperties, entityInstanceContext),
            };

            // Try to add the dynamic properties if the entity type is open.
            if ((entityInstanceContext.EntityType.IsOpen && selectExpandNode.SelectAllDynamicProperties) ||
                (entityInstanceContext.EntityType.IsOpen && selectExpandNode.SelectedDynamicProperties.Any()))
            {
                IEdmTypeReference entityTypeReference =
                    entityInstanceContext.EntityType.ToEdmTypeReference(isNullable: false);
                List<ODataProperty> dynamicProperties = AppendDynamicProperties(entityInstanceContext.EdmObject,
                    (IEdmStructuredTypeReference)entityTypeReference,
                    entityInstanceContext.SerializerContext,
                    entry.Properties.ToList(),
                    selectExpandNode.SelectedDynamicProperties.ToArray());

                if (dynamicProperties != null)
                {
                    entry.Properties = entry.Properties.Concat(dynamicProperties);
                }
            }

            IEnumerable<ODataAction> actions = CreateODataActions(selectExpandNode.SelectedActions, entityInstanceContext);
            foreach (ODataAction action in actions)
            {
                entry.AddAction(action);
            }

            IEnumerable<ODataFunction> functions = CreateODataFunctions(selectExpandNode.SelectedFunctions, entityInstanceContext);
            foreach (ODataFunction function in functions)
            {
                entry.AddFunction(function);
            }

            IEdmEntityType pathType = GetODataPathType(entityInstanceContext.SerializerContext);
            AddTypeNameAnnotationAsNeeded(entry, pathType, entityInstanceContext.SerializerContext.MetadataLevel);

            if (entityInstanceContext.NavigationSource != null)
            {
                if (!(entityInstanceContext.NavigationSource is IEdmContainedEntitySet))
                {
                    IEdmModel model = entityInstanceContext.SerializerContext.Model;
                    NavigationSourceLinkBuilderAnnotation linkBuilder = model.GetNavigationSourceLinkBuilder(entityInstanceContext.NavigationSource);
                    EntitySelfLinks selfLinks = linkBuilder.BuildEntitySelfLinks(entityInstanceContext, entityInstanceContext.SerializerContext.MetadataLevel);

                    if (selfLinks.IdLink != null)
                    {
                        entry.Id = selfLinks.IdLink;
                    }

                    if (selfLinks.ReadLink != null)
                    {
                        entry.ReadLink = selfLinks.ReadLink;
                    }

                    if (selfLinks.EditLink != null)
                    {
                        entry.EditLink = selfLinks.EditLink;
                    }
                }

                string etag = CreateETag(entityInstanceContext);
                if (etag != null)
                {
                    entry.ETag = etag;
                }
            }

            return entry;
        }
        public void InjectMetadataBuilderShouldNotSetBuilderOnEntryFunctions()
        {
            var entry = new ODataEntry();
            var builder = new TestEntityMetadataBuilder(entry);
            var function1 = new ODataFunction { Metadata = new Uri("http://service/$metadata#function1", UriKind.Absolute) };
            var function2 = new ODataFunction { Metadata = new Uri("http://service/$metadata#function2", UriKind.Absolute) };
            
            entry.AddFunction(function1);
            entry.AddFunction(function2);

            testSubject.InjectMetadataBuilder(entry, builder);
            function1.GetMetadataBuilder().Should().BeNull();
            function2.GetMetadataBuilder().Should().BeNull();
        }
        public void InjectMetadataBuilderShouldSetBuilderOnEntryFunctions()
        {
            var entry = new ODataEntry();
            var builder = new TestEntityMetadataBuilder(entry);
            var function1 = new ODataFunction { Metadata = new Uri(MetadataDocumentUri, "#function1") };
            var function2 = new ODataFunction { Metadata = new Uri(MetadataDocumentUri, "#function2") };

            entry.AddFunction(function1);
            entry.AddFunction(function2);

            testSubject.InjectMetadataBuilder(entry, builder);
            function1.GetMetadataBuilder().Should().BeSameAs(builder);
            function2.GetMetadataBuilder().Should().BeSameAs(builder);
        }
 public void ShouldWriteFunctionForRequestEntryPayloadWithUserModel()
 {
     ODataEntry entry = new ODataEntry { TypeName = "NS.MyDerivedEntityType" };
     entry.AddFunction(new ODataFunction {Metadata = new Uri("#Function1", UriKind.Relative)});
     const string expectedPayload = "{\"@odata.type\":\"#NS.MyDerivedEntityType\",\"#Function1\":{}}";
     Action action = () => this.WriteNestedItemsAndValidatePayload(entitySet: null, entityType: null, nestedItemToWrite: new[] { entry }, expectedPayload: expectedPayload, writingResponse: false);
     action.ShouldThrow<ODataException>().WithMessage(Strings.WriterValidationUtils_OperationInRequest("#Function1"));
 }
 public void ShouldWriteFunctionForResponseEntryPayloadWithUserModel()
 {
     ODataEntry entry = new ODataEntry { TypeName = "NS.MyDerivedEntityType" };
     entry.AddFunction(new ODataFunction { Metadata = new Uri("#Function1", UriKind.Relative) });
     const string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#MySet/$entity\",\"@odata.type\":\"#NS.MyDerivedEntityType\",\"#Function1\":{}}";
     this.WriteNestedItemsAndValidatePayload(entitySet: this.entitySet, entityType: null, nestedItemToWrite: new[] { entry }, expectedPayload: expectedPayload, writingResponse: true);
 }
        public void ActionAndFunctionPayloadOrderTest()
        {
            EdmModel model = new EdmModel();
            var container = new EdmEntityContainer("TestModel", "TestContainer");
            model.AddElement(container);

            var otherType = new EdmEntityType("TestModel", "OtherType");
            otherType.AddKeys(otherType.AddStructuralProperty("ID", EdmCoreModel.Instance.GetInt32(false)));
            model.AddElement(otherType);
            container.AddEntitySet("OtherType", otherType);

            var nonMLEBaseType = new EdmEntityType("TestModel", "NonMLEBaseType");
            nonMLEBaseType.AddKeys(nonMLEBaseType.AddStructuralProperty("ID", EdmCoreModel.Instance.GetInt32(false)));
            model.AddElement(nonMLEBaseType);
            var nonMLESet = container.AddEntitySet("NonMLESet", nonMLEBaseType);

            var nonMLEType = new EdmEntityType("TestModel", "NonMLEType", nonMLEBaseType);
            nonMLEType.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(true));
            nonMLEType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "NavProp", Target = otherType, TargetMultiplicity = EdmMultiplicity.Many });
            model.AddElement(nonMLEType);
            container.AddEntitySet("NonMLEType", nonMLEType);

            ODataAction action = new ODataAction
            {
                Metadata = new Uri("http://odata.org/test/$metadata#defaultAction"),
                Title = "Default Action",
                Target = new Uri("http://www.odata.org/defaultAction"),
            };

            ODataFunction function = new ODataFunction
            {
                Metadata = new Uri("http://odata.org/test/$metadata#defaultFunction()"),
                Title = "Default Function",
                Target = new Uri("defaultFunctionTarget", UriKind.Relative)
            };

            string defaultJson = string.Join("$(NL)",
                "{{",
                "{1}" +
                "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + "\":\"#TestModel.NonMLEType\"{0},\"#defaultAction\":{{",
                "\"title\":\"Default Action\",\"target\":\"http://www.odata.org/defaultAction\"",
                "}},\"#defaultFunction()\":{{",
                "\"title\":\"Default Function\",\"target\":\"defaultFunctionTarget\"",
                "}}",
                "}}");

            var entryWithActionAndFunction = new ODataEntry() { TypeName = "TestModel.NonMLEType", };
            entryWithActionAndFunction.AddAction(action);
            entryWithActionAndFunction.AddFunction(function);
            IEnumerable<EntryPayloadTestCase> testCases = new[]
            {
                new EntryPayloadTestCase
                {
                    DebugDescription = "Functions and actions available at the beginning.",
                    Entry = entryWithActionAndFunction,
                    Model = model,
                    EntitySet = nonMLESet,
                    Json = defaultJson
                },
            };

            IEnumerable<PayloadWriterTestDescriptor<ODataItem>> testDescriptors = testCases.Select(testCase =>
                new PayloadWriterTestDescriptor<ODataItem>(
                    this.Settings,
                    new ODataItem[] { testCase.Entry },
                    tc => new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                    {
                        Json = string.Format(CultureInfo.InvariantCulture, testCase.Json,
                            string.Empty,
                            tc.IsRequest ? string.Empty : (JsonLightWriterUtils.GetMetadataUrlPropertyForEntry(testCase.EntitySet.Name) + ",")),
                        FragmentExtractor = (result) => result.RemoveAllAnnotations(true)
                    })
                {
                    DebugDescription = testCase.DebugDescription,
                    Model = testCase.Model,
                    PayloadEdmElementContainer = testCase.EntitySet,
                    PayloadEdmElementType = testCase.EntityType,
                    SkipTestConfiguration = testCase.SkipTestConfiguration
                });

            testDescriptors = testDescriptors.Concat(testCases.Select(testCase =>
                new PayloadWriterTestDescriptor<ODataItem>(
                    this.Settings,
                    new ODataItem[] { testCase.Entry, new ODataNavigationLink
                    {
                        Name = "NavProp",
                        IsCollection = true,
                        Url = new Uri("http://odata.org/navprop/uri")
                    }},
                    tc => new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                    {
                        Json = string.Format(CultureInfo.InvariantCulture, testCase.Json,
                            tc.IsRequest ?
                                ",\"NavProp\":[$(NL){$(NL)\"__metadata\":{$(NL)\"uri\":\"http://odata.org/navprop/uri\"$(NL)}$(NL)}$(NL)]" :
                                ",\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + "\":\"http://odata.org/navprop/uri\"",
                                tc.IsRequest ? string.Empty : (JsonLightWriterUtils.GetMetadataUrlPropertyForEntry(testCase.EntitySet.Name) + ",")),
                        FragmentExtractor = (result) => result.RemoveAllAnnotations(true)
                    })
                {
                    DebugDescription = testCase.DebugDescription + "- with navigation property",
                    Model = testCase.Model,
                    PayloadEdmElementContainer = testCase.EntitySet,
                    PayloadEdmElementType = testCase.EntityType,
                    SkipTestConfiguration = testCase.SkipTestConfiguration
                }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors,
                // Actions/functions are only supported in responses.
                this.WriterTestConfigurationProvider.JsonLightFormatConfigurationsWithIndent.Where(tc => !tc.IsRequest),
                (testDescriptor, testConfiguration) =>
                {
                    TestWriterUtils.WriteAndVerifyODataEdmPayload(testDescriptor.DeferredLinksToEntityReferenceLinksInRequest(testConfiguration), testConfiguration, this.Assert, this.Logger);
                });
        }
        public void NoOpMetadataBuilderShouldReturnFunctionsSetByUser()
        {
            ODataFunction function = new ODataFunction()
            {
                Metadata = new Uri("http://example.com/$metadata#Function"),
                Target = new Uri("http://example.com/Function"),
                Title = "FunctionTitle"
            };

            ODataEntry entry = new ODataEntry();
            entry.AddFunction(function);

            new NoOpEntityMetadataBuilder(entry).GetFunctions()
                .Should().ContainSingle(f => f == function);
            
            // Verify that the Function information wasn't removed or changed.
            function.Metadata.Should().Be(new Uri("http://example.com/$metadata#Function"));
            function.Target.Should().Be(new Uri("http://example.com/Function"));
            function.Title.Should().Be("FunctionTitle");
        }