/// <summary>
        /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal.
        /// </summary>
        /// <param name="writer">The Xml writer to write to.</param>
        /// <param name="baseUri">The base Uri of the document or null if none was specified.</param>
        /// <param name="entry">The entry for which to write the association link.</param>
        /// <param name="associationLink">The association link for which to write the metadata.</param>
        internal static void WriteODataAssociationLinkMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, ODataAssociationLink associationLink)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(associationLink != null, "link != null");
            Debug.Assert(!string.IsNullOrEmpty(associationLink.Name), "The link name was not verified yet.");
            Debug.Assert(associationLink.Url != null, "The link Url was not verified yet.");

            string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink);
            string linkHref     = AtomUtils.ToUrlAttributeValue(associationLink.Url, baseUri);
            string linkHrefLang = null;
            string linkType     = MimeConstants.MimeApplicationXml;
            string linkTitle    = associationLink.Name;
            int?   linkLength   = null;

            AtomLinkMetadata  linkMetadata  = null;
            AtomEntryMetadata entryMetadata = entry.Atom();

            if (entryMetadata != null)
            {
                // TODO: Determine the link metadata from the entry
            }

            if (linkMetadata != null)
            {
                Uri metadataHref = linkMetadata.Href;
                if (metadataHref != null)
                {
                    string metadataHrefString = AtomUtils.ToUrlAttributeValue(metadataHref, baseUri);
                    if (metadataHrefString != linkHref)
                    {
                        throw new ODataException(Strings.ODataAtomWriter_LinkMetadataHrefMustBeEqualWithLinkUrl(metadataHrefString, linkHref));
                    }
                }

                string metadataRelation = linkMetadata.Relation;
                if (metadataRelation != null && metadataRelation != linkRelation)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataRelationMustBeEqualWithComputedRelation(metadataRelation, linkRelation));
                }

                string metadataType = linkMetadata.MediaType;
                if (metadataType != null && metadataType != linkType)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataMediaTypeMustBeEqualWithComputedType(metadataRelation, linkType));
                }

                string metadataTitle = linkMetadata.Title;
                if (metadataTitle != null && metadataTitle != linkTitle)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataTitleMustBeEqualWithLinkName(metadataTitle, linkTitle));
                }

                linkHrefLang = linkMetadata.HrefLang;
                linkLength   = linkMetadata.Length;
            }

            WriteAtomLinkMetadataAttributes(writer, linkRelation, linkHref, linkHrefLang, linkTitle, linkType, linkLength);
        }
Example #2
0
        public void EntryReadAndEditLinkMetadataWriterTest()
        {
            Func <XElement, XElement> fragmentExtractor = (e) => e.Element(TestAtomConstants.AtomXNamespace + "link");

            // Convert test cases to test descriptions; first for the entry's self link
            var selfLinkTestDescriptors = linkMetadataTestCases.Select(testCase =>
            {
                ODataEntry entry      = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                entry.Atom().SelfLink = testCase.LinkMetadata("self", readLinkHref);
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.ExpectedXml == null ? null : testCase.ExpectedXml("self", readLinkHref, null, null),
                    ExpectedException2 = testCase.ExpectedException == null ? null : testCase.ExpectedException("self", readLinkHref),
                    FragmentExtractor = fragmentExtractor
                }));
            });

            // now the ones for the entry's edit link
            var editLinkTestDescriptors = linkMetadataTestCases.Select(testCase =>
            {
                ODataEntry entry      = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                entry.ReadLink        = null;
                entry.EditLink        = new Uri(editLinkHref);
                entry.Atom().EditLink = testCase.LinkMetadata("edit", editLinkHref);
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.ExpectedXml == null ? null : testCase.ExpectedXml("edit", editLinkHref, null, null),
                    ExpectedException2 = testCase.ExpectedException == null ? null : testCase.ExpectedException("edit", editLinkHref),
                    FragmentExtractor = fragmentExtractor
                }));
            });

            var testDescriptors = selfLinkTestDescriptors.Concat(editLinkTestDescriptors);

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
Example #3
0
 protected override void StartEntry(ODataEntry entry)
 {
     this.CheckAndWriteParentNavigationLinkStartForInlineElement();
     if (entry != null)
     {
         this.StartEntryXmlCustomization(entry);
         this.atomOutputContext.XmlWriter.WriteStartElement("", "entry", "http://www.w3.org/2005/Atom");
         if (base.IsTopLevel)
         {
             this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes();
         }
         string eTag = entry.ETag;
         if (eTag != null)
         {
             ODataAtomWriterUtils.WriteETag(this.atomOutputContext.XmlWriter, eTag);
         }
         AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
         AtomEntryMetadata entryMetadata     = entry.Atom();
         string            id = entry.Id;
         if (id != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryId(id);
             currentEntryScope.SetWrittenElement(AtomElement.Id);
         }
         string typeName = entry.TypeName;
         SerializationTypeNameAnnotation annotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();
         if (annotation != null)
         {
             typeName = annotation.TypeName;
         }
         this.atomEntryAndFeedSerializer.WriteEntryTypeName(typeName, entryMetadata);
         Uri editLink = entry.EditLink;
         if (editLink != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
             currentEntryScope.SetWrittenElement(AtomElement.EditLink);
         }
         Uri readLink = entry.ReadLink;
         if (readLink != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
             currentEntryScope.SetWrittenElement(AtomElement.ReadLink);
         }
     }
 }
Example #4
0
        protected override void EndEntry(ODataEntry entry)
        {
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                this.CheckAndWriteParentNavigationLinkEndForInlineElement();
                return;
            }

            IEdmEntityType entryType = this.EntryEntityType;

            // Initialize the property value cache and cache the entry properties.
            EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry);

            // NOTE: when writing, we assume the model has been validated already and thus pass int.MaxValue for the maxMappingCount.
            ODataEntityPropertyMappingCache epmCache = this.atomOutputContext.Model.EnsureEpmCache(entryType, /*maxMappingCount*/ int.MaxValue);

            // Populate the property value cache based on the EPM source tree information.
            // We do this since we need to write custom EPM after the properties below and don't
            // want to cache all properties just for the case that they are used in a custom EPM.
            if (epmCache != null)
            {
                EpmWriterUtils.CacheEpmProperties(propertyValueCache, epmCache.EpmSourceTree);
            }

            // Get the projected properties annotation
            ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();

            AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
            AtomEntryMetadata entryMetadata     = entry.Atom();

            if (!currentEntryScope.IsElementWritten(AtomElement.Id))
            {
                // NOTE: We write even null id, in that case we generate an empty atom:id element.
                this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id);
            }

            Uri editLink = entry.EditLink;

            if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
            }

            Uri readLink = entry.ReadLink;

            if (readLink != null && !currentEntryScope.IsElementWritten(AtomElement.ReadLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
            }

            // write entry metadata including syndication EPM
            AtomEntryMetadata epmEntryMetadata = null;

            if (epmCache != null)
            {
                ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryType, this.atomOutputContext.Model);

                epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(
                    epmCache.EpmTargetTree,
                    propertyValueCache,
                    entryType.ToTypeReference().AsEntity(),
                    this.atomOutputContext);
            }

            this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime);

            // stream properties
            IEnumerable <ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties;

            if (streamProperties != null)
            {
                foreach (ODataProperty streamProperty in streamProperties)
                {
                    this.atomEntryAndFeedSerializer.WriteStreamProperty(
                        streamProperty,
                        entryType,
                        this.DuplicatePropertyNamesChecker,
                        projectedProperties);
                }
            }

            // association links
            IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks;

            if (associationLinks != null)
            {
                foreach (ODataAssociationLink associationLink in associationLinks)
                {
                    this.atomEntryAndFeedSerializer.WriteAssociationLink(
                        associationLink,
                        entryType,
                        this.DuplicatePropertyNamesChecker,
                        projectedProperties);
                }
            }

            // actions
            IEnumerable <ODataAction> actions = entry.Actions;

            if (actions != null)
            {
                foreach (ODataAction action in actions)
                {
                    ValidationUtils.ValidateOperationNotNull(action, true);
                    this.atomEntryAndFeedSerializer.WriteOperation(action);
                }
            }

            // functions
            IEnumerable <ODataFunction> functions = entry.Functions;

            if (functions != null)
            {
                foreach (ODataFunction function in functions)
                {
                    ValidationUtils.ValidateOperationNotNull(function, false);
                    this.atomEntryAndFeedSerializer.WriteOperation(function);
                }
            }

            // write the content
            this.WriteEntryContent(
                entry,
                entryType,
                propertyValueCache,
                epmCache == null ? null : epmCache.EpmSourceTree.Root,
                projectedProperties);

            // write custom EPM
            if (epmCache != null)
            {
                EpmCustomWriter.WriteEntryEpm(
                    this.atomOutputContext.XmlWriter,
                    epmCache.EpmTargetTree,
                    propertyValueCache,
                    entryType.ToTypeReference().AsEntity(),
                    this.atomOutputContext);
            }

            // </entry>
            this.atomOutputContext.XmlWriter.WriteEndElement();

            this.EndEntryXmlCustomization(entry);

            this.CheckAndWriteParentNavigationLinkEndForInlineElement();
        }
Example #5
0
        /// <summary>
        /// Start writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void StartEntry(ODataEntry entry)
        {
            this.CheckAndWriteParentNavigationLinkStartForInlineElement();
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                return;
            }

            this.StartEntryXmlCustomization(entry);

            // <entry>
            this.atomOutputContext.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomEntryElementName, AtomConstants.AtomNamespace);

            if (this.IsTopLevel)
            {
                this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes();
            }

            string etag = entry.ETag;

            if (etag != null)
            {
                // TODO, ckerer: if this is a top-level entry also put the ETag into the headers.
                ODataAtomWriterUtils.WriteETag(this.atomOutputContext.XmlWriter, etag);
            }

            AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
            AtomEntryMetadata entryMetadata     = entry.Atom();

            // Write the id if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            string entryId = entry.Id;

            if (entryId != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryId(entryId);
                currentEntryScope.SetWrittenElement(AtomElement.Id);
            }

            // <category term="type" scheme="odatascheme"/>
            // If no type information is provided, don't include the category element for type at all
            // NOTE: the validation of the type name is done by the core writer.
            string typeName = entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            this.atomEntryAndFeedSerializer.WriteEntryTypeName(typeName, entryMetadata);

            // Write the edit link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri editLink = entry.EditLink;

            if (editLink != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
                currentEntryScope.SetWrittenElement(AtomElement.EditLink);
            }

            // Write the self link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri readLink = entry.ReadLink;

            if (readLink != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
                currentEntryScope.SetWrittenElement(AtomElement.ReadLink);
            }
        }
Example #6
0
        protected override void EndEntry(ODataEntry entry)
        {
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                this.CheckAndWriteParentNavigationLinkEndForInlineElement();
                return;
            }

            IEdmEntityType entryType = this.EntryEntityType;

            // Initialize the property value cache and cache the entry properties.
            EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry);

            // Get the projected properties annotation
            AtomEntryScope currentEntryScope = this.CurrentEntryScope;
            ProjectedPropertiesAnnotation projectedProperties = GetProjectedPropertiesAnnotation(currentEntryScope);
            AtomEntryMetadata             entryMetadata       = entry.Atom();

            if (!currentEntryScope.IsElementWritten(AtomElement.Id))
            {
                // NOTE: We write even null id, in that case we generate an empty atom:id element.
                bool isTransient = entry.IsTransient;
                this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id, isTransient);
            }

            Uri editLink = entry.EditLink;

            if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
            }

            Uri readLink = entry.ReadLink;

            if (readLink != null && readLink != editLink && !currentEntryScope.IsElementWritten(AtomElement.ReadLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
            }

            // write entry metadata
            this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, this.updatedTime);

            // stream properties
            IEnumerable <ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties;

            if (streamProperties != null)
            {
                foreach (ODataProperty streamProperty in streamProperties)
                {
                    this.atomEntryAndFeedSerializer.WriteStreamProperty(
                        streamProperty,
                        entryType,
                        this.DuplicatePropertyNamesChecker,
                        projectedProperties);
                }
            }

            // actions
            IEnumerable <ODataAction> actions = entry.Actions;

            if (actions != null)
            {
                foreach (ODataAction action in actions)
                {
                    ValidationUtils.ValidateOperationNotNull(action, true);
                    this.atomEntryAndFeedSerializer.WriteOperation(action);
                }
            }

            // functions
            IEnumerable <ODataFunction> functions = entry.Functions;

            if (functions != null)
            {
                foreach (ODataFunction function in functions)
                {
                    ValidationUtils.ValidateOperationNotNull(function, false);
                    this.atomEntryAndFeedSerializer.WriteOperation(function);
                }
            }

            // write the content
            this.WriteEntryContent(
                entry,
                entryType,
                propertyValueCache,
                projectedProperties);

            this.WriteInstanceAnnotations(entry.InstanceAnnotations, currentEntryScope.InstanceAnnotationWriteTracker);

            // </entry>
            this.atomOutputContext.XmlWriter.WriteEndElement();

            this.CheckAndWriteParentNavigationLinkEndForInlineElement();
        }
Example #7
0
        protected override void EndEntry(ODataEntry entry)
        {
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                this.CheckAndWriteParentNavigationLinkEndForInlineElement();
                return;
            }

            IEdmEntityType entryType = this.EntryEntityType;

            // Initialize the property value cache and cache the entry properties.
            EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry);

            // Get the projected properties annotation
            AtomEntryScope currentEntryScope = this.CurrentEntryScope;
            ProjectedPropertiesAnnotation projectedProperties = GetProjectedPropertiesAnnotation(currentEntryScope);
            AtomEntryMetadata entryMetadata = entry.Atom();

            if (!currentEntryScope.IsElementWritten(AtomElement.Id))
            {
                // NOTE: We write even null id, in that case we generate an empty atom:id element.
                bool isTransient = entry.IsTransient;
                this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id, isTransient);
            }

            Uri editLink = entry.EditLink;
            if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
            }

            Uri readLink = entry.ReadLink;
            if (readLink != null && readLink != editLink && !currentEntryScope.IsElementWritten(AtomElement.ReadLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
            }

            // write entry metadata
            this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, this.updatedTime);

            // stream properties
            IEnumerable<ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties;
            if (streamProperties != null)
            {
                foreach (ODataProperty streamProperty in streamProperties)
                {
                    this.atomEntryAndFeedSerializer.WriteStreamProperty(
                        streamProperty, 
                        entryType, 
                        this.DuplicatePropertyNamesChecker, 
                        projectedProperties);
                }
            }

            // actions
            IEnumerable<ODataAction> actions = entry.Actions;
            if (actions != null)
            {
                foreach (ODataAction action in actions)
                {
                    ValidationUtils.ValidateOperationNotNull(action, true);
                    this.atomEntryAndFeedSerializer.WriteOperation(action);
                }
            }

            // functions
            IEnumerable<ODataFunction> functions = entry.Functions;
            if (functions != null)
            {
                foreach (ODataFunction function in functions)
                {
                    ValidationUtils.ValidateOperationNotNull(function, false);
                    this.atomEntryAndFeedSerializer.WriteOperation(function);
                }
            }

            // write the content
            this.WriteEntryContent(
                entry, 
                entryType, 
                propertyValueCache, 
                projectedProperties);

            this.WriteInstanceAnnotations(entry.InstanceAnnotations, currentEntryScope.InstanceAnnotationWriteTracker);

            // </entry>
            this.atomOutputContext.XmlWriter.WriteEndElement();

            this.CheckAndWriteParentNavigationLinkEndForInlineElement();
        }
Example #8
0
        /// <summary>
        /// Start writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void StartEntry(ODataEntry entry)
        {
            this.CheckAndWriteParentNavigationLinkStartForInlineElement();
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                return;
            }

            // <entry>
            this.atomOutputContext.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomEntryElementName, AtomConstants.AtomNamespace);

            if (this.IsTopLevel)
            {
                this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes();
                
                // Write metadata:context
                this.atomEntryAndFeedSerializer.TryWriteEntryContextUri(this.CurrentEntryScope.GetOrCreateTypeContext(this.atomOutputContext.Model, this.atomOutputContext.WritingResponse));  
            }

            string etag = entry.ETag;
            if (etag != null)
            {
                // TODO, ckerer: if this is a top-level entry also put the ETag into the headers.
                ODataAtomWriterUtils.WriteETag(this.atomOutputContext.XmlWriter, etag);
            }

            AtomEntryScope currentEntryScope = this.CurrentEntryScope;
            AtomEntryMetadata entryMetadata = entry.Atom();

            // Write the id if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri entryId = entry.Id;
            bool isTransient = entry.IsTransient;
            if (entryId != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryId(entryId, isTransient);
                currentEntryScope.SetWrittenElement(AtomElement.Id);
            }

            // <category term="type" scheme="odatascheme"/>
            // If no type information is provided, don't include the category element for type at all
            // NOTE: the validation of the type name is done by the core writer.
            string typeName = this.atomOutputContext.TypeNameOracle.GetEntryTypeNameForWriting(entry);
            this.atomEntryAndFeedSerializer.WriteEntryTypeName(typeName, entryMetadata);

            // Write the edit link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri editLink = entry.EditLink;
            if (editLink != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
                currentEntryScope.SetWrittenElement(AtomElement.EditLink);
            }

            // Write the self link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            // If readlink is identical to editlink, don't write readlink.
            Uri readLink = entry.ReadLink;
            if (readLink != null)
            {
                if (readLink != editLink)
                {
                    this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
                }
                
                currentEntryScope.SetWrittenElement(AtomElement.ReadLink);
            }

            this.WriteInstanceAnnotations(entry.InstanceAnnotations, currentEntryScope.InstanceAnnotationWriteTracker);
        }
        public void CategoryMetadataOnEntryWriterTest()
        {
            var testCases = this.CreateAtomCategoryTestCases();

            Func <XElement, XElement> fragmentExtractor = (e) =>
            {
                var categoryElement = e.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomCategoryElementName);
                return(categoryElement ?? new XElement("missingCategory"));
            };

            // Convert test cases to test descriptions
            IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testDescriptors = testCases.Select(testCase =>
            {
                ODataEntry entry           = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                metadata.Categories = new AtomCategoryMetadata[] { testCase.Category };
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = fragmentExtractor
                }));
            });

            // Add tests for category with type name
            string testTypeName = "TestModel.TestTypeName";
            string testLabel    = "Test category 1 label";
            var    categoryWithTypeNameTestCases = new[]
            {
                // Clean merge, no conflicts
                new AtomCategoryTestCase
                {
                    Category = new AtomCategoryMetadata()
                    {
                        Term   = null,
                        Scheme = null,
                        Label  = testLabel,
                    },
                    Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    ExpectedException = null
                },
                // Patch, conflicting values match
                new AtomCategoryTestCase
                {
                    Category = new AtomCategoryMetadata()
                    {
                        Term   = testTypeName,
                        Scheme = TestAtomConstants.ODataSchemeNamespace,
                        Label  = testLabel,
                    },
                    Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    ExpectedException = null
                },
                // Patch conflict on term
                new AtomCategoryTestCase
                {
                    Category = new AtomCategoryMetadata()
                    {
                        Term   = testTypeName.ToUpper(),
                        Scheme = TestAtomConstants.ODataSchemeNamespace,
                        Label  = testLabel,
                    },
                    Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategoryTermsMustMatch", testTypeName, testTypeName.ToUpper())
                },
                // Patch conflict on scheme
                new AtomCategoryTestCase
                {
                    Category = new AtomCategoryMetadata()
                    {
                        Term   = testTypeName,
                        Scheme = TestAtomConstants.ODataSchemeNamespace.ToUpper(),
                        Label  = testLabel,
                    },
                    Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategorySchemesMustMatch", TestAtomConstants.ODataSchemeNamespace, TestAtomConstants.ODataSchemeNamespace.ToUpper())
                },
            };

            testDescriptors = testDescriptors.Concat(categoryWithTypeNameTestCases.Select(testCase =>
            {
                ODataEntry entry           = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                entry.TypeName             = testTypeName;
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                metadata.CategoryWithTypeName = testCase.Category;
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = fragmentExtractor
                }));
            }));

            // Add all the categories as the category with type name on entry which has no type name.
            // This verifies that the writer won't write the category with type name if there's no type name.
            testDescriptors = testDescriptors.Concat(testCases.Select(testCase =>
            {
                ODataEntry entry           = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                metadata.CategoryWithTypeName = testCase.Category;
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = "<missingCategory />", ExpectedException2 = null, FragmentExtractor = fragmentExtractor
                }));
            }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
Example #10
0
        public void PersonMetadataWriterTest()
        {
            string testEmail = "*****@*****.**";
            string testName  = "Test Author 1";
            string testUri   = "http://odata.org/authors/1";

            var testCases = new[]
            {
                new
                {
                    Person = new AtomPersonMetadata()
                    {
                        Name  = testName,
                        Email = testEmail,
                        Uri   = new Uri(testUri)
                    },
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testName + @"</name>",
                        @"  <uri>" + testUri + @"</uri>",
                        @"  <email>" + testEmail + @"</email>",
                        @"</author>"),
                    ExpectedException = (string)null
                },
                new
                {
                    Person = new AtomPersonMetadata()
                    {
                        Name  = null,
                        Email = testEmail,
                        Uri   = new Uri(testUri)
                    },
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name />",
                        @"  <uri>" + testUri + @"</uri>",
                        @"  <email>" + testEmail + @"</email>",
                        @"</author>"),
                    ExpectedException = (string)null
                },
                new
                {
                    Person = new AtomPersonMetadata()
                    {
                        Name  = testName,
                        Email = null,
                        Uri   = null
                    },
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testName + @"</name>",
                        @"</author>"),
                    ExpectedException = (string)null
                },
                new
                {
                    Person = (AtomPersonMetadata)testName,
                    Xml    = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testName + @"</name>",
                        @"</author>"),
                    ExpectedException = (string)null
                },
            };

            Func <XElement, XElement> fragmentExtractor = (e) => e.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomAuthorElementName);

            // Convert test cases to test descriptions
            var testDescriptors = testCases.Select(testCase =>
            {
                ODataEntry entry           = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                metadata.Authors = new AtomPersonMetadata[] { testCase.Person };
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.Xml, ExpectedODataExceptionMessage = testCase.ExpectedException, FragmentExtractor = fragmentExtractor
                }));
            });

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
        /// <summary>
        /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal.
        /// </summary>
        /// <param name="writer">The Xml writer to write to.</param>
        /// <param name="baseUri">The base Uri of the document or null if none was specified.</param>
        /// <param name="entry">The entry for which to write the association link.</param>
        /// <param name="associationLink">The association link for which to write the metadata.</param>
        internal static void WriteODataAssociationLinkMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, ODataAssociationLink associationLink)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(associationLink != null, "link != null");
            Debug.Assert(!string.IsNullOrEmpty(associationLink.Name), "The link name was not verified yet.");
            Debug.Assert(associationLink.Url != null, "The link Url was not verified yet.");

            string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink);
            string linkHref = AtomUtils.ToUrlAttributeValue(associationLink.Url, baseUri);
            string linkHrefLang = null;
            string linkType = MimeConstants.MimeApplicationXml;
            string linkTitle = associationLink.Name;
            int? linkLength = null;

            AtomLinkMetadata linkMetadata = null;
            AtomEntryMetadata entryMetadata = entry.Atom();
            if (entryMetadata != null)
            {
                // TODO: Determine the link metadata from the entry
            }

            if (linkMetadata != null)
            {
                Uri metadataHref = linkMetadata.Href;
                if (metadataHref != null)
                {
                    string metadataHrefString = AtomUtils.ToUrlAttributeValue(metadataHref, baseUri);
                    if (metadataHrefString != linkHref)
                    {
                        throw new ODataException(Strings.ODataAtomWriter_LinkMetadataHrefMustBeEqualWithLinkUrl(metadataHrefString, linkHref));
                    }
                }

                string metadataRelation = linkMetadata.Relation;
                if (metadataRelation != null && metadataRelation != linkRelation)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataRelationMustBeEqualWithComputedRelation(metadataRelation, linkRelation));
                }

                string metadataType = linkMetadata.MediaType;
                if (metadataType != null && metadataType != linkType)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataMediaTypeMustBeEqualWithComputedType(metadataRelation, linkType));
                }

                string metadataTitle = linkMetadata.Title;
                if (metadataTitle != null && metadataTitle != linkTitle)
                {
                    throw new ODataException(Strings.ODataAtomWriter_LinkMetadataTitleMustBeEqualWithLinkName(metadataTitle, linkTitle));
                }

                linkHrefLang = linkMetadata.HrefLang;
                linkLength = linkMetadata.Length;
            }

            WriteAtomLinkMetadataAttributes(writer, linkRelation, linkHref, linkHrefLang, linkTitle, linkType, linkLength);
        }
        public void EntryMetadataWriterTest()
        {
            const string      testPublished = "2010-10-20T20:10:00Z";
            AtomTextConstruct testRights    = new AtomTextConstruct {
                Text = "Copyright Data Fx team."
            };
            AtomTextConstruct testSummary = new AtomTextConstruct {
                Text = "Test summary."
            };
            AtomTextConstruct testTitle = new AtomTextConstruct {
                Text = "Test title"
            };
            const string      testUpdated  = "2010-11-01T00:04:00Z";
            const string      testIcon     = "http://odata.org/icon";
            const string      testSourceId = "http://odata.org/id/random";
            const string      testLogo     = "http://odata.org/logo";
            AtomTextConstruct testSubtitle = new AtomTextConstruct {
                Text = "Test subtitle."
            };

            const string testAuthorName  = "Test Author 1";
            const string testAuthorEmail = "*****@*****.**";
            const string testAuthorUri   = "http://odata.org/authors/1";

            var testAuthors = new AtomPersonMetadata[]
            {
                new AtomPersonMetadata()
                {
                    Email = testAuthorEmail,
                    Name  = testAuthorName,
                    Uri   = new Uri(testAuthorUri)
                }
            };

            var testAuthors2 = new AtomPersonMetadata[0];

            const string testCategoryTerm   = "Test category 1 term";
            const string testCategoryLabel  = "Test category 1 label";
            const string testCategoryScheme = "http://odata.org/categories/1";

            var testCategories = new AtomCategoryMetadata[]
            {
                new AtomCategoryMetadata()
                {
                    Term   = testCategoryTerm,
                    Label  = testCategoryLabel,
                    Scheme = testCategoryScheme
                }
            };

            const string testContributorName  = "Test Contributor 1";
            const string testContributorEmail = "*****@*****.**";
            const string testContributorUri   = "http://odata.org/contributors/1";

            var testContributors = new AtomPersonMetadata[]
            {
                new AtomPersonMetadata()
                {
                    Email = testContributorEmail,
                    Name  = testContributorName,
                    Uri   = new Uri(testContributorUri)
                }
            };

            const string testGeneratorName    = "Test generator";
            const string testGeneratorUri     = "http://odata.org/generator";
            const string testGeneratorVersion = "3.0";

            var testGenerator = new AtomGeneratorMetadata()
            {
                Name    = testGeneratorName,
                Uri     = new Uri(testGeneratorUri),
                Version = testGeneratorVersion
            };

            const string testLinkRelation  = "http://odata.org/links/1";
            const string testLinkTitle     = "Test link 1";
            const string testLinkHref      = "http://odata.org/links/1";
            const string testLinkHrefLang  = "de-AT";
            int?         testLinkLength    = 999;
            const string testLinkMediaType = "image/png";

            var testLinks = new AtomLinkMetadata[]
            {
                new AtomLinkMetadata()
                {
                    Relation  = testLinkRelation,
                    Title     = testLinkTitle,
                    Href      = new Uri(testLinkHref),
                    HrefLang  = testLinkHrefLang,
                    Length    = testLinkLength,
                    MediaType = testLinkMediaType
                }
            };

            AtomFeedMetadata testSource = new AtomFeedMetadata()
            {
                Authors      = testAuthors,
                Categories   = testCategories,
                Contributors = testContributors,
                Generator    = testGenerator,
                Icon         = new Uri(testIcon),
                SourceId     = new Uri(testSourceId),
                Links        = testLinks,
                Logo         = new Uri(testLogo),
                Rights       = testRights,
                Subtitle     = testSubtitle,
                Title        = testTitle,
                Updated      = DateTimeOffset.Parse(testUpdated)
            };

            Func <string, Func <XElement, XElement> > fragmentExtractor = (localName) => (e) => e.Element(TestAtomConstants.AtomXNamespace + localName);

            // TODO, ckerer: specify an Id via metadata if the entry does not specify one; we first have to decide what rules
            //               we want to apply to merging of metadata and ODataLib OM data.
            var testCases = new[] {
                new { // specify an author via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testAuthorName + @"</name>",
                        @"  <uri>" + testAuthorUri + @"</uri>",
                        @"  <email>" + testAuthorEmail + @"</email>",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify an empty author array via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors2),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name />",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify no authors via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = null),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"$(Indent)<name />",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify a category via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Categories = testCategories),
                    Xml       = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName)
                },
                new { // specify a contributor via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Contributors = testContributors),
                    Xml = string.Join(
                        "$(NL)",
                        @"<contributor xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testContributorName + @"</name>",
                        @"  <uri>" + testContributorUri + @"</uri>",
                        @"  <email>" + testContributorEmail + @"</email>",
                        @"</contributor>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomContributorElementName)
                },
                new { // specify a link via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Links = testLinks),
                    Xml       = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = new Func <XElement, XElement>(
                        (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                        .Where(l => l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value != TestAtomConstants.AtomSelfRelationAttributeValue)
                        .Single())
                },
                new { // specify a published date via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Published = DateTimeOffset.Parse(testPublished)),
                    Xml       = @"<published xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testPublished + @"</published>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomPublishedElementName)
                },
                new { // specify rights via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Rights = testRights),
                    Xml       = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName)
                },
                new { // specify a source via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = testSource),
                    Xml = string.Join(
                        "$(NL)",
                        @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <id>" + testSourceId + "</id>",
                        @"  <title type=""text"">" + testTitle.Text + @"</title>",
                        @"  <subtitle type=""text"">" + testSubtitle.Text + @"</subtitle>",
                        @"  <updated>" + testUpdated + @"</updated>",
                        @"  <link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""/>",
                        @"  <category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" />",
                        @"  <logo>" + testLogo + @"</logo>",
                        @"  <rights type=""text"">" + testRights.Text + @"</rights>",
                        @"  <contributor>",
                        @"    <name>" + testContributorName + @"</name>",
                        @"    <uri>" + testContributorUri + @"</uri>",
                        @"    <email>" + testContributorEmail + @"</email>",
                        @"  </contributor>",
                        @"  <generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""">" + testGeneratorName + @"</generator>",
                        @"  <icon>" + testIcon + @"</icon>",
                        @"  <author>",
                        @"    <name>" + testAuthorName + @"</name>",
                        @"    <uri>" + testAuthorUri + @"</uri>",
                        @"    <email>" + testAuthorEmail + @"</email>",
                        @"  </author>",
                        @"</source>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomSourceElementName)
                },
                new { // specify default feed metadata as source
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = new AtomFeedMetadata()),
                    Xml = string.Join(
                        "$(NL)",
                        @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <id />",
                        @"  <title />",
                        @"  <updated />",
                        @"</source>"),
                    Extractor = new Func <XElement, XElement>(result => {
                        var source = fragmentExtractor(TestAtomConstants.AtomSourceElementName)(result);
                        // Remove the value of updates as it can't be reliably predicted
                        source.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomUpdatedElementName).Nodes().Remove();
                        return(source);
                    })
                },
                new { // specify a summary via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Summary = testSummary),
                    Xml       = @"<summary type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSummary.Text + @"</summary>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomSummaryElementName)
                },
                new { // specify a title via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Title = testTitle),
                    Xml       = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName)
                },
                new { // specify an updated date via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated)),
                    Xml       = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName)
                },
            };

            // Convert test cases to test descriptions
            IEnumerable <Func <ODataEntry> > entryCreators = new Func <ODataEntry>[]
            {
                () => ObjectModelUtils.CreateDefaultEntry(),
                () => ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(),
            };
            var testDescriptors = testCases.SelectMany(testCase =>
                                                       entryCreators.Select(entryCreator =>
            {
                ODataEntry entry           = entryCreator();
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                testCase.CustomizeMetadata(metadata);
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.Xml, FragmentExtractor = testCase.Extractor
                }));
            }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
Example #13
0
 protected override void EndEntry(ODataEntry entry)
 {
     if (entry == null)
     {
         this.CheckAndWriteParentNavigationLinkEndForInlineElement();
     }
     else
     {
         IEdmEntityType                  entryEntityType    = base.EntryEntityType;
         EntryPropertiesValueCache       propertyValueCache = new EntryPropertiesValueCache(entry);
         ODataEntityPropertyMappingCache cache2             = this.atomOutputContext.Model.EnsureEpmCache(entryEntityType, 0x7fffffff);
         if (cache2 != null)
         {
             EpmWriterUtils.CacheEpmProperties(propertyValueCache, cache2.EpmSourceTree);
         }
         ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();
         AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
         AtomEntryMetadata entryMetadata     = entry.Atom();
         if (!currentEntryScope.IsElementWritten(AtomElement.Id))
         {
             this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id);
         }
         Uri editLink = entry.EditLink;
         if ((editLink != null) && !currentEntryScope.IsElementWritten(AtomElement.EditLink))
         {
             this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
         }
         Uri readLink = entry.ReadLink;
         if ((readLink != null) && !currentEntryScope.IsElementWritten(AtomElement.ReadLink))
         {
             this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
         }
         AtomEntryMetadata epmEntryMetadata = null;
         if (cache2 != null)
         {
             ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryEntityType, this.atomOutputContext.Model);
             epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext);
         }
         this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime);
         IEnumerable <ODataProperty> entryStreamProperties = propertyValueCache.EntryStreamProperties;
         if (entryStreamProperties != null)
         {
             foreach (ODataProperty property in entryStreamProperties)
             {
                 this.atomEntryAndFeedSerializer.WriteStreamProperty(property, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties);
             }
         }
         IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks;
         if (associationLinks != null)
         {
             foreach (ODataAssociationLink link in associationLinks)
             {
                 this.atomEntryAndFeedSerializer.WriteAssociationLink(link, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties);
             }
         }
         IEnumerable <ODataAction> actions = entry.Actions;
         if (actions != null)
         {
             foreach (ODataAction action in actions)
             {
                 ValidationUtils.ValidateOperationNotNull(action, true);
                 this.atomEntryAndFeedSerializer.WriteOperation(action);
             }
         }
         IEnumerable <ODataFunction> functions = entry.Functions;
         if (functions != null)
         {
             foreach (ODataFunction function in functions)
             {
                 ValidationUtils.ValidateOperationNotNull(function, false);
                 this.atomEntryAndFeedSerializer.WriteOperation(function);
             }
         }
         this.WriteEntryContent(entry, entryEntityType, propertyValueCache, (cache2 == null) ? null : cache2.EpmSourceTree.Root, projectedProperties);
         if (cache2 != null)
         {
             EpmCustomWriter.WriteEntryEpm(this.atomOutputContext.XmlWriter, cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext);
         }
         this.atomOutputContext.XmlWriter.WriteEndElement();
         this.EndEntryXmlCustomization(entry);
         this.CheckAndWriteParentNavigationLinkEndForInlineElement();
     }
 }