private ODataStreamReferenceValue GetMediaResource(object element, ResourceType entityResourceType, string title, Uri relativeUri) { ODataStreamReferenceValue value2 = null; if (entityResourceType.IsMediaLinkEntry) { string str; Uri uri; string str2; base.Service.StreamProvider.GetStreamDescription(element, null, base.Service.OperationContext, out str, out uri, out str2); Uri uri2 = RequestUriProcessor.AppendEscapedSegment(relativeUri, "$value"); value2 = new ODataStreamReferenceValue { EditLink = uri2, ContentType = str2, ReadLink = uri ?? uri2 }; AtomStreamReferenceMetadata metadata2 = new AtomStreamReferenceMetadata(); AtomLinkMetadata metadata3 = new AtomLinkMetadata { Title = title }; metadata2.EditLink = metadata3; AtomStreamReferenceMetadata annotation = metadata2; value2.SetAnnotation <AtomStreamReferenceMetadata>(annotation); if (!string.IsNullOrEmpty(str)) { value2.ETag = str; } } return(value2); }
/// <summary> /// Adds a new link to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLink(this AtomEntryMetadata entryMetadata, AtomLinkMetadata linkMetadata) { Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); entryMetadata.Links = entryMetadata.Links.ConcatToReadOnlyEnumerable("Ref", linkMetadata); }
/// <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); }
/// <summary> /// Adds a new link to feed metadata. /// </summary> /// <param name="feedMetadata">The feed metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLink(this AtomFeedMetadata feedMetadata, AtomLinkMetadata linkMetadata) { Debug.Assert(feedMetadata != null, "feedMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); feedMetadata.Links = feedMetadata.Links.ConcatToReadOnlyEnumerable("Ref", linkMetadata); }
/// <summary> /// Visits a stream reference value item. /// </summary> /// <param name="streamReferenceValue">The stream reference value item to visit.</param> /// <returns>An ODataPayloadElement representing the stream reference value.</returns> protected override ODataPayloadElement VisitStreamReferenceValue(ODataStreamReferenceValue streamReferenceValue) { ExceptionUtilities.CheckArgumentNotNull(streamReferenceValue, "streamReferenceValue"); NamedStreamInstance namedStreamInstance = (NamedStreamInstance)base.VisitStreamReferenceValue(streamReferenceValue); AtomStreamReferenceMetadata streamMetadata = streamReferenceValue.GetAnnotation <AtomStreamReferenceMetadata>(); if (streamMetadata != null) { if (streamMetadata.EditLink != null) { AtomLinkMetadata editMetadata = streamMetadata.EditLink; namedStreamInstance.AtomNamedStreamLink(editMetadata.Href == null ? null : editMetadata.Href.OriginalString, editMetadata.Relation, editMetadata.MediaType, editMetadata.HrefLang, editMetadata.Title, ToString(editMetadata.Length)); } if (streamMetadata.SelfLink != null) { AtomLinkMetadata selfMetadata = streamMetadata.SelfLink; namedStreamInstance.AtomNamedStreamLink(selfMetadata.Href == null ? null : selfMetadata.Href.OriginalString, selfMetadata.Relation, selfMetadata.MediaType, selfMetadata.HrefLang, selfMetadata.Title, ToString(selfMetadata.Length)); } } return(namedStreamInstance); }
internal static void AddLinkToFeedMetadata(AtomFeedMetadata feedMetadata, AtomLinkMetadata linkMetadata) { if (object.ReferenceEquals(feedMetadata.Links, EmptyLinksList)) { feedMetadata.Links = new ReadOnlyEnumerable <AtomLinkMetadata>(); } ReaderUtils.GetSourceListOfEnumerable <AtomLinkMetadata>(feedMetadata.Links, "Links").Add(linkMetadata); }
/// <summary> /// Adds a new link to feed metadata. /// </summary> /// <param name="feedMetadata">The feed metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLink(this AtomFeedMetadata feedMetadata, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(feedMetadata != null, "feedMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); feedMetadata.Links = feedMetadata.Links.ConcatToReadOnlyEnumerable("Links", linkMetadata); }
private static void AddLinkMetadata(DeferredLink payloadElement, ODataNavigationLink link) { AtomLinkMetadata metadata = CreateLinkMetadata(payloadElement.Annotations.OfType <XmlTreeAnnotation>()); if (metadata != null) { link.SetAnnotation <AtomLinkMetadata>(metadata); } }
/// <summary> /// Converts the Object Model representation of Atom link metadata into appropriate annotations for a link ODataPayloadElement. /// </summary> /// <param name="linkMetadata">The Atom link metadata, in Object Model representation, to convert.</param> /// <param name="payloadElement">The payload element to annotate.</param> private static void ConvertAtomLinkMetadata(AtomLinkMetadata linkMetadata, ODataPayloadElement payloadElement) { ExceptionUtilities.CheckArgumentNotNull(linkMetadata, "linkMetadata"); ExceptionUtilities.CheckArgumentNotNull(payloadElement, "link"); string lengthValue = linkMetadata.Length.HasValue ? linkMetadata.Length.Value.ToString() : null; payloadElement.AtomLink(linkMetadata.Href == null ? null : linkMetadata.Href.OriginalString, linkMetadata.Relation, linkMetadata.MediaType, linkMetadata.HrefLang, linkMetadata.Title, lengthValue); }
private void WriteEntry(IExpandedResult expanded, object element, bool resourceInstanceInFeed, ResourceType expectedType) { Uri uri; Func <ProjectionNode, bool> predicate = null; base.IncrementSegmentResultCount(); ODataEntry entry = new ODataEntry(); AtomEntryMetadata annotation = new AtomEntryMetadata(); entry.SetAnnotation <AtomEntryMetadata>(annotation); string name = expectedType.Name; ResourceType actualResourceType = WebUtil.GetNonPrimitiveResourceType(base.Provider, element); if (actualResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw new DataServiceException(500, System.Data.Services.Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(actualResourceType.FullName)); } Uri absoluteUri = Serializer.GetIdAndEditLink(element, actualResourceType, base.Provider, base.CurrentContainer, base.AbsoluteServiceUri, out uri); Uri relativeUri = new Uri(absoluteUri.AbsoluteUri.Substring(base.AbsoluteServiceUri.AbsoluteUri.Length), UriKind.Relative); entry.MediaResource = this.GetMediaResource(element, actualResourceType, name, relativeUri); entry.TypeName = actualResourceType.FullName; entry.Id = uri.AbsoluteUri; entry.EditLink = relativeUri; AtomLinkMetadata metadata2 = new AtomLinkMetadata { Title = name }; annotation.EditLink = metadata2; string eTagValue = base.GetETagValue(element, actualResourceType); if (eTagValue != null) { entry.ETag = eTagValue; } IEnumerable <ProjectionNode> projections = base.GetProjections(); if (projections != null) { if (predicate == null) { predicate = projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(actualResourceType); } projections = projections.Where <ProjectionNode>(predicate); entry.SetAnnotation <ProjectedPropertiesAnnotation>(new ProjectedPropertiesAnnotation(from p in projections select p.PropertyName)); } entry.AssociationLinks = this.GetEntityAssociationLinks(actualResourceType, relativeUri, projections); this.PopulateODataOperations(element, resourceInstanceInFeed, entry, actualResourceType); this.odataWriter.WriteStart(entry); this.WriteNavigationProperties(expanded, element, resourceInstanceInFeed, actualResourceType, absoluteUri, relativeUri, projections); entry.Properties = this.GetEntityProperties(element, actualResourceType, relativeUri, projections); this.odataWriter.WriteEnd(); }
private static AtomLinkMetadata CreateLinkMetadata(IEnumerable <XmlTreeAnnotation> children) { AtomLinkMetadata metadata = new AtomLinkMetadata(); bool initialized = false; foreach (XmlTreeAnnotation epmTree in children.Where(child => child.IsAttribute)) { string localName = epmTree.LocalName; if (localName == TestAtomConstants.AtomLinkHrefAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.Href = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); initialized = true; } else if (localName == TestAtomConstants.AtomLinkHrefLangAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.HrefLang = epmTree.PropertyValue; initialized = true; } else if (localName == TestAtomConstants.AtomLinkLengthAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.Length = string.IsNullOrEmpty(epmTree.PropertyValue) ? (int?)null : int.Parse(epmTree.PropertyValue); initialized = true; } else if (localName == TestAtomConstants.AtomLinkRelationAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.Relation = epmTree.PropertyValue; initialized = true; } else if (localName == TestAtomConstants.AtomLinkTitleAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.Title = epmTree.PropertyValue; initialized = true; } else if (localName == TestAtomConstants.AtomLinkTypeAttributeName) { Debug.Assert(epmTree.IsAttribute); metadata.MediaType = epmTree.PropertyValue; initialized = true; } else { throw new NotSupportedException("Unsupported metadata '" + localName + "' found for a link."); } } return(initialized ? metadata : null); }
/// <summary> /// Adds a new link to feed metadata. /// </summary> /// <param name="feedMetadata">The feed metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLinkToFeedMetadata(AtomFeedMetadata feedMetadata, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(feedMetadata != null, "feedMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); if (object.ReferenceEquals(feedMetadata.Links, EmptyLinksList)) { feedMetadata.Links = new ReadOnlyEnumerable <AtomLinkMetadata>(); } ReaderUtils.GetSourceListOfEnumerable(feedMetadata.Links, "Links").Add(linkMetadata); }
/// <summary> /// Visits an entity reference links item. /// </summary> /// <param name="entityReferenceLinks">The entity reference links item to visit.</param> /// <returns>An ODataPayloadElement representing the entity reference links.</returns> protected override ODataPayloadElement VisitEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { ExceptionUtilities.CheckArgumentNotNull(entityReferenceLinks, "entityReferenceLinks"); LinkCollection linkCollection = (LinkCollection)base.VisitEntityReferenceLinks(entityReferenceLinks); AtomLinkMetadata atomMetadata = entityReferenceLinks.GetAnnotation <AtomLinkMetadata>(); if (atomMetadata != null) { ConvertAtomLinkMetadata(atomMetadata, linkCollection); } return(linkCollection); }
/// <summary> /// Write the metadata of a link in ATOM format /// </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="linkMetadata">The link metadata to write.</param> internal static void WriteAtomLinkMetadata(XmlWriter writer, Uri baseUri, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); Debug.Assert(linkMetadata != null, "Link metadata must not be null."); // <atom:link ... > writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); string linkHref = linkMetadata.Href == null ? null : AtomUtils.ToUrlAttributeValue(linkMetadata.Href, baseUri); WriteAtomLinkMetadataAttributes(writer, linkMetadata.Relation, linkHref, linkMetadata.HrefLang, linkMetadata.Title, linkMetadata.MediaType, linkMetadata.Length); // </atom:link> writer.WriteEndElement(); }
/// <summary> /// Converts the Object Model representation of Atom link metadata into appropriate annotations for a payload element representing a link. /// </summary> /// <param name="linkMetadata">The Atom link metadata, in Object Model representation, to convert.</param> /// <param name="linkPayloadElement">The link payload element to annotate.</param> /// <remarks>This method is only for use with payload elements that represent links, as it will skip over the root link annotation.</remarks> private static void ConvertAtomLinkChildrenMetadata(AtomLinkMetadata linkMetadata, ODataPayloadElement linkPayloadElement) { ExceptionUtilities.CheckArgumentNotNull(linkMetadata, "linkMetadata"); ExceptionUtilities.CheckArgumentNotNull(linkPayloadElement, "linkPayloadElement"); // Since the payload element already represents a link, we annotate a temporary element // and copy the "children" annotations onto the actual payload element. var tempPayloadElement = new EntityInstance(); ExceptionUtilities.Assert(!tempPayloadElement.Annotations.OfType <XmlTreeAnnotation>().Any(), "Payload element should not have XmlTreeAnnotations after construction"); ConvertAtomLinkMetadata(linkMetadata, tempPayloadElement); XmlTreeAnnotation linkAnnotation = tempPayloadElement.Annotations.OfType <XmlTreeAnnotation>().Single(); foreach (XmlTreeAnnotation childAnnotation in linkAnnotation.Children) { linkPayloadElement.AddAnnotation(childAnnotation); } }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> /// <returns>An ODataPayloadElement representing the navigation link.</returns> protected override ODataPayloadElement VisitNavigationLink(ODataNavigationLink navigationLink) { ExceptionUtilities.CheckArgumentNotNull(navigationLink, "navigationLink"); NavigationPropertyInstance navigationProperty = (NavigationPropertyInstance)base.VisitNavigationLink(navigationLink); // In ATOM even deferred links may know if they point to collection or singleton. // So add the content type annotation to them (through it IsCollection) so that comparison is precise. DeferredLink deferredLink = navigationProperty.Value as DeferredLink; if (deferredLink != null && navigationLink.IsCollection.HasValue) { deferredLink.IsCollection(navigationLink.IsCollection.Value); } AtomLinkMetadata atomMetadata = navigationLink.GetAnnotation <AtomLinkMetadata>(); if (atomMetadata != null && deferredLink != null) { ConvertAtomLinkChildrenMetadata(atomMetadata, navigationProperty.Value); } return(navigationProperty); }
public void NavigationLinkMetadataWriterTest() { string testRelation = "http://docs.oasis-open.org/odata/ns/related/SampleLinkName"; string testIncorrectRelation = "http://odata.org/relation/1"; string testTitle = "SampleLinkName"; string testIncorrectTitle = "Test link 1"; string testHref = "http://odata.org/link"; string testIncorrectHref = "http://odata.org/links/1"; string testHrefLang = "de-AT"; int? testLength = 999; string testMediaType = "application/atom+xml;type=feed"; string testIncorrectMediaType = "image/png"; var testCases = new[] { new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testRelation; metadata.Title = testTitle; metadata.Href = new Uri(testHref); metadata.HrefLang = testHrefLang; metadata.Length = testLength; metadata.MediaType = testMediaType; link.Url = metadata.Href; }), Xml = @"<link rel=""" + testRelation + @""" type = """ + testMediaType + @""" title=""" + testTitle + @""" href=""" + testHref + @""" hreflang=""" + testHrefLang + @""" length=""" + testLength.Value + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = (ExpectedException)null }, new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testRelation; metadata.Title = testTitle; metadata.Href = new Uri(testIncorrectHref); metadata.HrefLang = testHrefLang; metadata.Length = testLength; metadata.MediaType = testMediaType; }), Xml = (string)null, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkHrefsMustMatch", "http://odata.org/link", "http://odata.org/links/1"), }, new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testIncorrectRelation; metadata.Title = testTitle; metadata.Href = new Uri(testHref); metadata.HrefLang = testHrefLang; metadata.Length = testLength; metadata.MediaType = testMediaType; }), Xml = (string)null, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "http://docs.oasis-open.org/odata/ns/related/SampleLinkName", "http://odata.org/relation/1"), }, new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testRelation; metadata.Title = testTitle; metadata.Href = new Uri(testHref); metadata.HrefLang = testHrefLang; metadata.Length = testLength; metadata.MediaType = testIncorrectMediaType; }), Xml = (string)null, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkMediaTypesMustMatch", "application/atom+xml;type=feed", "image/png"), }, new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testRelation; metadata.Title = testIncorrectTitle; metadata.Href = new Uri(testHref); metadata.HrefLang = testHrefLang; metadata.Length = testLength; metadata.MediaType = testMediaType; }), Xml = (string)null, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkTitlesMustMatch", "SampleLinkName", "Test link 1"), }, new { CustomizeLink = new Action <ODataNavigationLink>( (link) => { AtomLinkMetadata metadata = link.Atom(); metadata.Relation = testRelation; metadata.Title = null; metadata.Href = new Uri(testHref); metadata.HrefLang = null; metadata.Length = null; metadata.MediaType = null; }), Xml = @"<link rel=""" + testRelation + @""" type = """ + testMediaType + @""" title=""" + testTitle + @""" href=""" + testHref + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = (ExpectedException)null }, }; Func <XElement, XElement> fragmentExtractor = (e) => e; // Convert test cases to test descriptions Func <ODataNavigationLink>[] linkCreators = new Func <ODataNavigationLink>[] { () => ObjectModelUtils.CreateDefaultCollectionLink(), () => { var link = ObjectModelUtils.CreateDefaultCollectionLink(); link.SetAnnotation(new AtomLinkMetadata()); return(link); } }; var testDescriptors = testCases.SelectMany(testCase => linkCreators.Select(linkCreator => { ODataNavigationLink link = linkCreator(); testCase.CustomizeLink(link); return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, link, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = fragmentExtractor })); })); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.NavigationLinkPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor.DeferredLinksToEntityReferenceLinksInRequest(testConfiguration), testConfiguration, this.Assert, this.Logger); }); }
/// <summary> /// Writes the syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="resourceType">The resource type of the entry.</param> /// <param name="metadata">The metadata provider to use.</param> /// <param name="version">The version of OData protocol to use.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> internal static AtomEntryMetadata WriteEntryEpm( EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available."); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return null; } AtomEntryMetadata entryMetadata = new AtomEntryMetadata(); foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.IsMultiValueProperty) { Debug.Assert( targetSegment.EpmInfo != null && targetSegment.EpmInfo.Attribute != null, "MultiValue property target segment must have EpmInfo and the Epm Attribute."); ODataVersionChecker.CheckMultiValueProperties(version, targetSegment.EpmInfo.Attribute.SourcePath); // WriteMultiValueEpm(entry, targetSegment, epmValueCache); throw new NotImplementedException(); } else if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); bool nullOnParentProperty; object propertyValue = epmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: entryMetadata.Updated = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, version); break; case SyndicationItemProperty.Published: entryMetadata.Published = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, version); break; case SyndicationItemProperty.Rights: entryMetadata.Rights = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Summary: entryMetadata.Summary = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Title: entryMetadata.Title = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Authors == null, "Found two mappings to author, that is invalid."); if (authorMetadata != null) { entryMetadata.Authors = CreateSinglePersonList(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Contributors == null, "Found two mappings to contributor, that is invalid."); if (contributorMetadata != null) { entryMetadata.Contributors = CreateSinglePersonList(contributorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomLinkElementName) { AtomLinkMetadata linkMetadata = new AtomLinkMetadata(); //// WriteLinkEpm(entry, targetSegment, epmValueCache); Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to link must be conditional."); linkMetadata.Relation = targetSegment.CriteriaValue; List<AtomLinkMetadata> links; if (entryMetadata.Links == null) { links = new List<AtomLinkMetadata>(); entryMetadata.Links = links; } else { links = entryMetadata.Links as List<AtomLinkMetadata>; Debug.Assert(links != null, "AtomEntryMetadata.Links must be of type List<AtomLinkMetadata> since we create it like that."); } links.Add(linkMetadata); throw new NotImplementedException(); } else if (targetSegment.SegmentName == AtomConstants.AtomCategoryElementName) { AtomCategoryMetadata categoryMetadata = new AtomCategoryMetadata(); //// WriteCategoryEpm(entry, targetSegment, epmValueCache) Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to category must be conditional."); categoryMetadata.Scheme = targetSegment.CriteriaValue; List<AtomCategoryMetadata> categories; if (entryMetadata.Categories == null) { categories = new List<AtomCategoryMetadata>(); entryMetadata.Categories = categories; } else { categories = entryMetadata.Links as List<AtomCategoryMetadata>; Debug.Assert(categories != null, "AtomEntryMetadata.Categories must be of type List<AtomCategoryMetadata> since we create it like that."); } categories.Add(categoryMetadata); throw new NotImplementedException(); } else { throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_TargetSegment)); } } return entryMetadata; }
private static AtomFeedMetadata CreateFeedMetadata(IEnumerable <XmlTreeAnnotation> children, ODataFeed feed) { AtomFeedMetadata metadata = null; foreach (XmlTreeAnnotation epmTree in children) { if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace) { if (metadata == null) { metadata = new AtomFeedMetadata(); } string localName = epmTree.LocalName; if (localName == TestAtomConstants.AtomAuthorElementName) { AtomPersonMetadata author = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> authors; if (metadata.Authors == null) { authors = new List <AtomPersonMetadata>(); metadata.Authors = authors; } else { authors = (List <AtomPersonMetadata>)metadata.Authors; } authors.Add(author); } else if (localName == TestAtomConstants.AtomCategoryElementName) { AtomCategoryMetadata category = CreateCategoryMetadata(epmTree.Children); List <AtomCategoryMetadata> categories; if (metadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); metadata.Categories = categories; } else { categories = (List <AtomCategoryMetadata>)metadata.Categories; } categories.Add(category); } else if (localName == TestAtomConstants.AtomContributorElementName) { AtomPersonMetadata contributor = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> contributors; if (metadata.Contributors == null) { contributors = new List <AtomPersonMetadata>(); metadata.Contributors = contributors; } else { contributors = (List <AtomPersonMetadata>)metadata.Contributors; } contributors.Add(contributor); } else if (localName == TestAtomConstants.AtomGeneratorElementName) { metadata.Generator = CreateGeneratorMetadata(epmTree); } else if (localName == TestAtomConstants.AtomIconElementName) { metadata.Icon = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomIdElementName) { Debug.Assert(!epmTree.IsAttribute); Uri id = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue, UriKind.Absolute); if (feed == null) { // we are creating the metadata for an entry's 'source' metadata; // we don't have a feed to store the Id on so it has to go into metadata metadata.SourceId = id; } else { feed.Id = id; } } else if (localName == TestAtomConstants.AtomLinkElementName) { AtomLinkMetadata link = CreateLinkMetadata(epmTree.Children); List <AtomLinkMetadata> links; if (metadata.Links == null) { links = new List <AtomLinkMetadata>(); metadata.Links = links; } else { links = (List <AtomLinkMetadata>)metadata.Contributors; } links.Add(link); } else if (localName == TestAtomConstants.AtomLogoElementName) { metadata.Logo = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomRightsElementName) { AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Rights = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomSubtitleElementName) { AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Subtitle = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomTitleElementName) { AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Title = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomUpdatedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Updated = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else { throw new NotSupportedException("Unsupported atom metadata found!"); } } } return(metadata); }
public void FeedMetadataWriterTest() { AtomTextConstruct testRights = new AtomTextConstruct { Text = "Copyright Data Fx team." }; AtomTextConstruct testTitle = new AtomTextConstruct { Text = "Test title" }; AtomTextConstruct testSubtitle = new AtomTextConstruct { Text = "Test subtitle" }; const string testUpdated = "2010-11-01T00:04:00Z"; const string testIcon = "http://odata.org/icon"; const string testLogo = "http://odata.org/logo"; 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) } }; 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 } }; var selfLink = new AtomLinkMetadata() { Relation = TestAtomConstants.AtomSelfRelationAttributeValue, Title = testLinkTitle, Href = new Uri(testLinkHref), HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }; 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 FeedMetadataTestCase[] { new FeedMetadataTestCase { // specify an icon via metadata CustomizeMetadata = metadata => metadata.Icon = new Uri(testIcon), Xml = @"<icon xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testIcon + @"</icon>", Extractor = fragmentExtractor(TestAtomConstants.AtomIconElementName) }, new FeedMetadataTestCase { // specify a logo via metadata CustomizeMetadata = metadata => metadata.Logo = new Uri(testLogo), Xml = @"<logo xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testLogo + @"</logo>", Extractor = fragmentExtractor(TestAtomConstants.AtomLogoElementName) }, new FeedMetadataTestCase { // specify rights via metadata CustomizeMetadata = metadata => metadata.Rights = testRights, Xml = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>", Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName) }, new FeedMetadataTestCase { // specify a subtitle via metadata CustomizeMetadata = metadata => metadata.Subtitle = testSubtitle, Xml = @"<subtitle type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSubtitle.Text + @"</subtitle>", Extractor = fragmentExtractor(TestAtomConstants.AtomSubtitleElementName) }, new FeedMetadataTestCase { // specify a title via metadata CustomizeMetadata = metadata => metadata.Title = testTitle, Xml = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>", Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName) }, new FeedMetadataTestCase { // specify an updated date via metadata CustomizeMetadata = metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated), Xml = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>", Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName) }, new FeedMetadataTestCase { // no author specified, the default author with empty name is written CustomizeMetadata = metadata => metadata.Authors = null, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new FeedMetadataTestCase { // specify an author via metadata CustomizeMetadata = 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 FeedMetadataTestCase { // no author specified but some entries written, no author should be written CustomizeMetadata = metadata => metadata.Authors = null, CustomizePayload = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() }, Xml = "<authors />", Extractor = result => new XElement("authors", fragmentExtractor(TestAtomConstants.AtomAuthorElementName)(result)) }, new FeedMetadataTestCase { // specify an author via metadata and some entries (the author should be written anyway) CustomizeMetadata = metadata => metadata.Authors = testAuthors, CustomizePayload = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() }, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new FeedMetadataTestCase { // specify a category via metadata CustomizeMetadata = metadata => metadata.Categories = testCategories, Xml = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName) }, new FeedMetadataTestCase { // specify a contributor via metadata CustomizeMetadata = 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 FeedMetadataTestCase { // specify a generator via metadata CustomizeMetadata = metadata => metadata.Generator = testGenerator, Xml = @"<generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testGeneratorName + @"</generator>", Extractor = fragmentExtractor(TestAtomConstants.AtomGeneratorElementName) }, new FeedMetadataTestCase { // specify a link via metadata CustomizeMetadata = metadata => metadata.Links = testLinks, Xml = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Single() }, new FeedMetadataTestCase { // no self link specified CustomizeMetadata = metadata => metadata.SelfLink = null, Xml = @"<selflink/>", Extractor = (e) => new XElement("selflink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue)) }, new FeedMetadataTestCase { // Some self link specified CustomizeMetadata = metadata => metadata.SelfLink = selfLink, Xml = @"<link rel=""" + TestAtomConstants.AtomSelfRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue) }, new FeedMetadataTestCase { // Non-self relation CustomizeMetadata = metadata => metadata.SelfLink = new AtomLinkMetadata { Relation = "SelF", Href = new Uri(testLinkHref) }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "self", "SelF"), }, new FeedMetadataTestCase { // no next link on either OM or metadata specified CustomizeMetadata = metadata => metadata.NextPageLink = null, Xml = @"<nextlink/>", Extractor = (e) => new XElement("nextlink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // the next link is only specified on metadata - nothing is written CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = "next", Href = new Uri(testLinkHref) }, Xml = @"<nextlink/>", Extractor = (e) => new XElement("nextlink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified only on the OM CustomizeMetadata = metadata => metadata.NextPageLink = null, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" href=""" + testLinkHref + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts cause values are identical CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = TestAtomConstants.AtomNextRelationAttributeValue, Href = new Uri(testLinkHref), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on relation CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = "Next", Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "next", "Next"), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on href CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Href = new Uri("http://odata.org/different"), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkHrefsMustMatch", testLinkHref, "http://odata.org/different"), SkipTestConfiguration = tc => tc.IsRequest }, }; this.CreateTestDescriptorsAndRunTests(testCases, WriterPayloads.FeedPayloads); }
/// <summary> /// Writes the syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="resourceType">The resource type of the entry.</param> /// <param name="metadata">The metadata provider to use.</param> /// <param name="version">The version of OData protocol to use.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> internal static AtomEntryMetadata WriteEntryEpm( EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available."); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return(null); } AtomEntryMetadata entryMetadata = new AtomEntryMetadata(); foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.IsMultiValueProperty) { Debug.Assert( targetSegment.EpmInfo != null && targetSegment.EpmInfo.Attribute != null, "MultiValue property target segment must have EpmInfo and the Epm Attribute."); ODataVersionChecker.CheckMultiValueProperties(version, targetSegment.EpmInfo.Attribute.SourcePath); // WriteMultiValueEpm(entry, targetSegment, epmValueCache); throw new NotImplementedException(); } else if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); bool nullOnParentProperty; object propertyValue = epmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: entryMetadata.Updated = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, version); break; case SyndicationItemProperty.Published: entryMetadata.Published = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, version); break; case SyndicationItemProperty.Rights: entryMetadata.Rights = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Summary: entryMetadata.Summary = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Title: entryMetadata.Title = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Authors == null, "Found two mappings to author, that is invalid."); if (authorMetadata != null) { entryMetadata.Authors = CreateSinglePersonList(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Contributors == null, "Found two mappings to contributor, that is invalid."); if (contributorMetadata != null) { entryMetadata.Contributors = CreateSinglePersonList(contributorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomLinkElementName) { AtomLinkMetadata linkMetadata = new AtomLinkMetadata(); //// WriteLinkEpm(entry, targetSegment, epmValueCache); Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to link must be conditional."); linkMetadata.Relation = targetSegment.CriteriaValue; List <AtomLinkMetadata> links; if (entryMetadata.Links == null) { links = new List <AtomLinkMetadata>(); entryMetadata.Links = links; } else { links = entryMetadata.Links as List <AtomLinkMetadata>; Debug.Assert(links != null, "AtomEntryMetadata.Links must be of type List<AtomLinkMetadata> since we create it like that."); } links.Add(linkMetadata); throw new NotImplementedException(); } else if (targetSegment.SegmentName == AtomConstants.AtomCategoryElementName) { AtomCategoryMetadata categoryMetadata = new AtomCategoryMetadata(); //// WriteCategoryEpm(entry, targetSegment, epmValueCache) Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to category must be conditional."); categoryMetadata.Scheme = targetSegment.CriteriaValue; List <AtomCategoryMetadata> categories; if (entryMetadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); entryMetadata.Categories = categories; } else { categories = entryMetadata.Links as List <AtomCategoryMetadata>; Debug.Assert(categories != null, "AtomEntryMetadata.Categories must be of type List<AtomCategoryMetadata> since we create it like that."); } categories.Add(categoryMetadata); throw new NotImplementedException(); } else { throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_TargetSegment)); } } return(entryMetadata); }
private static void AddEntryMetadata(EntityInstance payloadElement, ODataEntry entry) { AtomEntryMetadata metadata = null; foreach (XmlTreeAnnotation epmTree in payloadElement.Annotations.OfType <XmlTreeAnnotation>()) { if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace) { if (metadata == null) { metadata = new AtomEntryMetadata(); } string localName = epmTree.LocalName; if (localName == TestAtomConstants.AtomAuthorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata author = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> authors; if (metadata.Authors == null) { authors = new List <AtomPersonMetadata>(); metadata.Authors = authors; } else { authors = (List <AtomPersonMetadata>)metadata.Authors; } authors.Add(author); } else if (localName == TestAtomConstants.AtomCategoryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomCategoryMetadata category = CreateCategoryMetadata(epmTree.Children); List <AtomCategoryMetadata> categories; if (metadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); metadata.Categories = categories; } else { categories = (List <AtomCategoryMetadata>)metadata.Categories; } categories.Add(category); } else if (localName == TestAtomConstants.AtomContributorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata contributor = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> contributors; if (metadata.Contributors == null) { contributors = new List <AtomPersonMetadata>(); metadata.Contributors = contributors; } else { contributors = (List <AtomPersonMetadata>)metadata.Contributors; } contributors.Add(contributor); } else if (localName == TestAtomConstants.AtomIdElementName) { Debug.Assert(!epmTree.IsAttribute); entry.Id = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomLinkElementName) { Debug.Assert(!epmTree.IsAttribute); AtomLinkMetadata link = CreateLinkMetadata(epmTree.Children); List <AtomLinkMetadata> links; if (metadata.Links == null) { links = new List <AtomLinkMetadata>(); metadata.Links = links; } else { links = (List <AtomLinkMetadata>)metadata.Links; } links.Add(link); } else if (localName == TestAtomConstants.AtomPublishedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Published = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomRightsElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Rights = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomSourceElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Source = CreateFeedMetadata(epmTree.Children, null); } else if (localName == TestAtomConstants.AtomSummaryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Summary = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomTitleElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Title = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomUpdatedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Updated = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else { throw new NotSupportedException("Unsupported atom metadata '" + localName + "' found for entry!"); } } } // Fix up metadata for baselining metadata = metadata.Fixup(); if (metadata != null) { entry.SetAnnotation <AtomEntryMetadata>(metadata); } }
/// <summary> /// Converts the Object Model representation of Atom metadata for entries into appropriate PayloadElement annotations /// </summary> /// <param name="entryMetadata">the Atom entry metadata, in Object Model representation, to convert</param> /// <param name="entry">the EntityInstance to annotate</param> private static void ConvertAtomEntryMetadata(AtomEntryMetadata entryMetadata, EntityInstance entry) { ExceptionUtilities.CheckArgumentNotNull(entryMetadata, "entryMetadata"); ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); foreach (var author in entryMetadata.Authors) { entry.AtomAuthor(author.Name, author.Uri == null ? null : author.Uri.OriginalString, author.Email); } foreach (var category in entryMetadata.Categories) { entry.AtomCategory(category.Term, category.Scheme, category.Label); } foreach (var contributor in entryMetadata.Contributors) { entry.AtomContributor(contributor.Name, contributor.Uri == null? null : contributor.Uri.OriginalString, contributor.Email); } if (entryMetadata.EditLink != null) { AtomLinkMetadata editLink = entryMetadata.EditLink; entry.AtomEditLink(editLink.Href == null ? null : editLink.Href.OriginalString, editLink.MediaType, editLink.HrefLang, editLink.Title, ToString(editLink.Length)); } foreach (var link in entryMetadata.Links) { entry.AtomLink(link.Href == null ? null : link.Href.OriginalString, link.Relation, link.MediaType, link.HrefLang, link.Title, ToString(link.Length)); } if (entryMetadata.Published.HasValue) { entry.AtomPublished(ToString(entryMetadata.Published)); } if (entryMetadata.Rights != null) { entry.AtomRights(entryMetadata.Rights.Text, ToString(entryMetadata.Rights.Kind)); } if (entryMetadata.SelfLink != null) { AtomLinkMetadata selfLink = entryMetadata.SelfLink; entry.AtomSelfLink(selfLink.Href == null ? null : selfLink.Href.OriginalString, selfLink.MediaType, selfLink.HrefLang, selfLink.Title, ToString(selfLink.Length)); } if (entryMetadata.CategoryWithTypeName != null) { AtomCategoryMetadata categoryWithTypeName = entryMetadata.CategoryWithTypeName; entry.AtomCategoryWithTypeName(categoryWithTypeName.Term, categoryWithTypeName.Label); } if (entryMetadata.Source != null) { EntitySetInstance tempSourceFeed = new EntitySetInstance(); ConvertAtomFeedMetadata(entryMetadata.Source, tempSourceFeed); entry.AtomSource(tempSourceFeed); } if (entryMetadata.Summary != null) { entry.AtomSummary(entryMetadata.Summary.Text, ToString(entryMetadata.Summary.Kind)); } if (entryMetadata.Title != null) { entry.AtomTitle(entryMetadata.Title.Text, ToString(entryMetadata.Title.Kind)); } if (entryMetadata.Updated.HasValue) { entry.AtomUpdated(ToString(entryMetadata.Updated)); } }
/// <summary> /// Visits an ATOM link metadata. /// </summary> /// <param name="atomLinkMetadata">The link metadata to visit.</param> protected virtual void VisitAtomLinkMetadata(AtomLinkMetadata atomLinkMetadata) { }
/// <summary> /// Visits an ATOM metadata object. /// </summary> /// <param name="atomMetadata"></param> protected virtual void VisitAtomMetadata(object atomMetadata) { if (atomMetadata == null) { return; } AtomCategoryMetadata atomCategoryMetadata = atomMetadata as AtomCategoryMetadata; if (atomCategoryMetadata != null) { this.VisitAtomCategoryMetadata(atomCategoryMetadata); return; } AtomEntryMetadata atomEntryMetadata = atomMetadata as AtomEntryMetadata; if (atomEntryMetadata != null) { this.VisitAtomEntryMetadata(atomEntryMetadata); return; } AtomFeedMetadata atomFeedMetadata = atomMetadata as AtomFeedMetadata; if (atomFeedMetadata != null) { this.VisitAtomFeedMetadata(atomFeedMetadata); return; } AtomGeneratorMetadata atomGeneratorMetadata = atomMetadata as AtomGeneratorMetadata; if (atomGeneratorMetadata != null) { this.VisitAtomGeneratorMetadata(atomGeneratorMetadata); return; } AtomLinkMetadata atomLinkMetadata = atomMetadata as AtomLinkMetadata; if (atomLinkMetadata != null) { this.VisitAtomLinkMetadata(atomLinkMetadata); return; } AtomPersonMetadata atomPersonMetadata = atomMetadata as AtomPersonMetadata; if (atomPersonMetadata != null) { this.VisitAtomPersonMetadata(atomPersonMetadata); return; } AtomResourceCollectionMetadata atomResourceCollectionMetadata = atomMetadata as AtomResourceCollectionMetadata; if (atomResourceCollectionMetadata != null) { this.VisitAtomResourceCollectionMetadata(atomResourceCollectionMetadata); return; } AtomStreamReferenceMetadata atomStreamReferenceMetadata = atomMetadata as AtomStreamReferenceMetadata; if (atomStreamReferenceMetadata != null) { this.VisitAtomStreamReferenceMetadata(atomStreamReferenceMetadata); return; } AtomTextConstruct atomTextConstruct = atomMetadata as AtomTextConstruct; if (atomTextConstruct != null) { this.VisitAtomTextConstruct(atomTextConstruct); return; } AtomWorkspaceMetadata atomWorkspaceMetadata = atomMetadata as AtomWorkspaceMetadata; if (atomWorkspaceMetadata != null) { this.VisitAtomWorkspaceMetadata(atomWorkspaceMetadata); return; } AtomCategoriesMetadata atomCategoriesMetadata = atomMetadata as AtomCategoriesMetadata; if (atomCategoriesMetadata != null) { this.VisitAtomCategoriesMetadata(atomCategoriesMetadata); return; } ExceptionUtilities.Assert(false, "Unrecognized ATOM metadata object {0} of type {1}.", atomMetadata.ToString(), atomMetadata.GetType().ToString()); }
/// <summary> /// Write the metadata of a link in ATOM format /// </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="linkMetadata">The link metadata to write.</param> internal static void WriteAtomLinkMetadata(XmlWriter writer, Uri baseUri, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); Debug.Assert(linkMetadata != null, "Link metadata must not be null."); // <atom:link ... > writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); string linkHref = linkMetadata.Href == null ? null : AtomUtils.ToUrlAttributeValue(linkMetadata.Href, baseUri); WriteAtomLinkMetadataAttributes(writer, linkMetadata.Relation, linkHref, linkMetadata.HrefLang, linkMetadata.Title, linkMetadata.MediaType, linkMetadata.Length); // </atom:link> writer.WriteEndElement(); }
/// <summary> /// Converts the Object Model representation of Atom metadata for feeds into appropriate PayloadElement annotations /// </summary> /// <param name="feedMetadata">the Atom feed metadata, in Object Model representation, to convert</param> /// <param name="feed">the EntitySetInstance to annotate</param> private static void ConvertAtomFeedMetadata(AtomFeedMetadata feedMetadata, EntitySetInstance feed) { ExceptionUtilities.CheckArgumentNotNull(feedMetadata, "feedMetadata"); ExceptionUtilities.CheckArgumentNotNull(feed, "feed"); foreach (var author in feedMetadata.Authors) { feed.AtomAuthor(author.Name, author.Uri == null ? null : author.Uri.OriginalString, author.Email); } foreach (var category in feedMetadata.Categories) { feed.AtomCategory(category.Term, category.Scheme, category.Label); } foreach (var contributor in feedMetadata.Contributors) { feed.AtomContributor(contributor.Name, contributor.Uri == null ? null : contributor.Uri.OriginalString, contributor.Email); } if (feedMetadata.Generator != null) { feed.AtomGenerator(feedMetadata.Generator.Name, feedMetadata.Generator.Uri == null ? null : feedMetadata.Generator.Uri.OriginalString, feedMetadata.Generator.Version); } if (feedMetadata.Icon != null) { feed.AtomIcon(feedMetadata.Icon.OriginalString); } foreach (var link in feedMetadata.Links) { string linkLength = link.Length.HasValue ? link.Length.Value.ToString() : null; feed.AtomLink(link.Href == null ? null : link.Href.OriginalString, link.Relation, link.MediaType, link.HrefLang, link.Title, linkLength); } if (feedMetadata.Logo != null) { feed.AtomLogo(feedMetadata.Logo.OriginalString); } if (feedMetadata.Rights != null) { feed.AtomRights(feedMetadata.Rights.Text, ToString(feedMetadata.Rights.Kind)); } if (feedMetadata.SelfLink != null) { AtomLinkMetadata selfLink = feedMetadata.SelfLink; ExceptionUtilities.Assert(selfLink.Relation == TestAtomConstants.AtomSelfRelationAttributeValue, "The self link ATOM metadata must have the rel set to 'self'."); string selfLinkLength = selfLink.Length.HasValue ? selfLink.Length.Value.ToString() : null; feed.AtomSelfLink(selfLink.Href == null ? null : selfLink.Href.OriginalString, selfLink.MediaType, selfLink.HrefLang, selfLink.Title, selfLinkLength); } if (feedMetadata.NextPageLink != null) { AtomLinkMetadata nextPageLink = feedMetadata.NextPageLink; ExceptionUtilities.Assert(nextPageLink.Relation == TestAtomConstants.AtomNextRelationAttributeValue, "The next page link ATOM metadata must have the rel set to 'next'."); string nextPageLinkLength = nextPageLink.Length.HasValue ? nextPageLink.Length.Value.ToString() : null; feed.AtomNextPageLink(nextPageLink.Href == null ? null : nextPageLink.Href.OriginalString, nextPageLink.MediaType, nextPageLink.HrefLang, nextPageLink.Title, nextPageLinkLength); } if (feedMetadata.SourceId != null) { // This should only occur when the metadata comes from the source element of an entry // and we are annotating a temporary feed instance feed.AtomId(UriUtils.UriToString(feedMetadata.SourceId)); } if (feedMetadata.Subtitle != null) { feed.AtomSubtitle(feedMetadata.Subtitle.Text, ToString(feedMetadata.Subtitle.Kind)); } if (feedMetadata.Title != null) { feed.AtomTitle(feedMetadata.Title.Text, ToString(feedMetadata.Title.Kind)); } if (feedMetadata.Updated.HasValue) { feed.AtomUpdated(ToString(feedMetadata.Updated)); } }
private void WriteFeedElements(IExpandedResult expanded, IEnumerator elements, ResourceType expectedType, string title, Uri relativeUri, Uri absoluteUri, bool hasMoved, bool topLevel) { ODataFeed feed = new ODataFeed { Id = absoluteUri.AbsoluteUri }; AtomFeedMetadata annotation = new AtomFeedMetadata(); feed.SetAnnotation <AtomFeedMetadata>(annotation); AtomTextConstruct construct = new AtomTextConstruct { Text = title }; annotation.Title = construct; AtomLinkMetadata metadata2 = new AtomLinkMetadata { Href = relativeUri, Title = title }; annotation.SelfLink = metadata2; bool flag = false; if (topLevel && (base.RequestDescription.CountOption == RequestQueryCountOption.Inline)) { flag = this.contentFormat == ODataFormat.VerboseJson; if (!flag) { feed.Count = new long?(base.RequestDescription.CountValue); } } this.odataWriter.WriteStart(feed); try { object lastObject = null; IExpandedResult skipTokenExpandedResult = null; while (hasMoved) { object current = elements.Current; IExpandedResult skipToken = base.GetSkipToken(expanded); if (current != null) { IExpandedResult result3 = current as IExpandedResult; if (result3 != null) { expanded = result3; current = Serializer.GetExpandedElement(expanded); skipToken = base.GetSkipToken(expanded); } this.WriteEntry(expanded, current, true, expectedType); } hasMoved = elements.MoveNext(); lastObject = current; skipTokenExpandedResult = skipToken; } if (flag) { feed.Count = new long?(base.RequestDescription.CountValue); } if (base.NeedNextPageLink(elements)) { feed.NextPageLink = base.GetNextLinkUri(lastObject, skipTokenExpandedResult, absoluteUri); } } finally { if (!topLevel) { WebUtil.Dispose(elements); } } this.odataWriter.WriteEnd(); }
/// <summary> /// Visits an ATOM link metadata. /// </summary> /// <param name="atomLinkMetadata">The link metadata to visit.</param> protected override void VisitAtomLinkMetadata(AtomLinkMetadata atomLinkMetadata) { this.ValidateUri(atomLinkMetadata.Href); base.VisitAtomLinkMetadata(atomLinkMetadata); }
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); }); }