From 06397983d3c9c94aaf2d577534209d8af8cea476 Mon Sep 17 00:00:00 2001 From: Hugh Bellamy Date: Tue, 5 Mar 2019 19:49:26 +0000 Subject: [PATCH] Add more Syndication tests (dotnet/corefx#35107) * Add more Syndication tests Commit migrated from https://github.com/dotnet/corefx/commit/013fd82b1bb218d171300e127a487ebc39e1fc2e --- .../System.ServiceModel.Syndication.Tests.csproj | 1 + .../Syndication/Atom10FeedFormatterTests.cs | 46 +- .../Syndication/Rss20FeedFormatterTests.cs | 2041 ++++++++++++++++++++ .../Syndication/Rss20ItemFormatterTests.cs | 34 +- .../Syndication/SyndicationFeedTests.cs | 28 +- .../Syndication/SyndicationFeedTests.netcoreapp.cs | 197 ++ .../netcoreapp/BasicScenarioTests.netcoreapp.cs | 57 - 7 files changed, 2344 insertions(+), 60 deletions(-) create mode 100644 src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20FeedFormatterTests.cs diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj b/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj index a244d8c..d7021a0 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj +++ b/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj @@ -6,6 +6,7 @@ + diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Atom10FeedFormatterTests.cs b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Atom10FeedFormatterTests.cs index fcb68ef..4429cb7 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Atom10FeedFormatterTests.cs +++ b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Atom10FeedFormatterTests.cs @@ -1071,7 +1071,7 @@ namespace System.ServiceModel.Syndication.Tests } Assert.Equal("contributor_email", itemThirdContributor.Email); Assert.Equal("contributor_name", itemThirdContributor.Name); - Assert.Equal("contributor_uri", thirdContributor.Uri); + Assert.Equal("contributor_uri", itemThirdContributor.Uri); if (preserveAttributeExtensions) { @@ -1779,6 +1779,50 @@ namespace System.ServiceModel.Syndication.Tests }); } + [Theory] + [InlineData(true, true)] + [InlineData(false, false)] + public void Read_CustomReadItems_ReturnsExpected(bool preserveAttributeExtensions, bool preserveElementExtensions) + { + using (var stringReader = new StringReader(@"")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new CustomAtom10FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + + SyndicationFeed feed = formatter.Feed; + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Single(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + } + } + + private class CustomAtom10FeedFormatter : Atom10FeedFormatter + { + protected override IEnumerable ReadItems(XmlReader reader, SyndicationFeed feed, out bool areAllItemsRead) + { + areAllItemsRead = false; + return new SyndicationItem[] { new SyndicationItem() }; + } + } + private static void VerifyRead(string xmlString, bool preserveAttributeExtensions, bool preserveElementExtensions, Action verifyAction) { // ReadFrom. diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20FeedFormatterTests.cs b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20FeedFormatterTests.cs new file mode 100644 index 0000000..a0deab1 --- /dev/null +++ b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20FeedFormatterTests.cs @@ -0,0 +1,2041 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Serialization; +using Xunit; + +namespace System.ServiceModel.Syndication.Tests +{ + public partial class Rss20FeedFormatterTests + { + [Fact] + public void Ctor_Default() + { + var formatter = new Formatter(); + Assert.Null(formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Fact] + public void Ctor_GenericDefault() + { + var formatter = new GenericFormatter(); + Assert.Null(formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Fact] + public void Ctor_SyndicationFeed() + { + var feed = new SyndicationFeed(); + var formatter = new Formatter(feed); + Assert.Same(feed, formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Fact] + public void Ctor_GenericSyndicationFeed() + { + var feed = new SyndicationFeed(); + var formatter = new GenericFormatter(feed); + Assert.Same(feed, formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Ctor_SyndicationFeed_Bool(bool serializeExtensionsAsAtom) + { + var feed = new SyndicationFeed(); + var formatter = new Formatter(feed, serializeExtensionsAsAtom); + Assert.Same(feed, formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Ctor_GenericSyndicationFeed_Bool(bool serializeExtensionsAsAtom) + { + var feed = new SyndicationFeed(); + var formatter = new GenericFormatter(feed, serializeExtensionsAsAtom); + Assert.Same(feed, formatter.Feed); + Assert.Equal(typeof(SyndicationFeed), formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Fact] + public void Ctor_NullFeedToWrite_ThrowsArgumentNullException() + { + AssertExtensions.Throws("feedToWrite", () => new Rss20FeedFormatter((SyndicationFeed)null)); + AssertExtensions.Throws("feedToWrite", () => new Rss20FeedFormatter(null)); + } + + [Theory] + [InlineData(typeof(SyndicationFeed))] + [InlineData(typeof(SyndicationFeedSubclass))] + public void Ctor_Type(Type feedTypeToCreate) + { + var formatter = new Formatter(feedTypeToCreate); + Assert.Null(formatter.Feed); + Assert.Equal(feedTypeToCreate, formatter.FeedTypeEntryPoint); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + + [Fact] + public void Ctor_NullFeedTypeToCreate_ThrowsArgumentNullException() + { + AssertExtensions.Throws("feedTypeToCreate", () => new Rss20FeedFormatter((Type)null)); + } + + [Fact] + public void Ctor_InvalidFeedTypeToCreate_ThrowsArgumentException() + { + AssertExtensions.Throws("feedTypeToCreate", () => new Rss20FeedFormatter(typeof(int))); + } + + [Fact] + public void GetSchema_Invoke_ReturnsNull() + { + IXmlSerializable formatter = new Rss20FeedFormatter(); + Assert.Null(formatter.GetSchema()); + } + + public static IEnumerable WriteTo_TestData() + { + // Empty item. + foreach (bool serializeExtensionsAsAtom in new bool[] { true, false }) + { + yield return new object[] + { + new SyndicationFeed(), + serializeExtensionsAsAtom, +@" + + <description /> + </channel>" + }; + } + + // Full item. + SyndicationPerson CreatePerson(string prefix) + { + var person = new SyndicationPerson(); + person.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name1"), null); + person.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name2", prefix + "_namespace"), ""); + person.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name3", prefix + "_namespace"), prefix + "_value"); + person.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name4", "xmlns"), ""); + + person.ElementExtensions.Add(new ExtensionObject { Value = 10 }); + + person.Email = prefix + "_email"; + + person.Name = prefix + "_name"; + + person.Uri = prefix + "_uri"; + + return person; + } + + TextSyndicationContent CreateContent(string prefix) + { + var content = new TextSyndicationContent(prefix + "_title", TextSyndicationContentKind.Html); + + content.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name1"), null); + content.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name2", prefix + "_namespace"), ""); + content.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name3", prefix + "_namespace"), prefix + "_value"); + content.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name4", "xmlns"), ""); + + return content; + } + + SyndicationCategory CreateCategory(string prefix) + { + var category = new SyndicationCategory(); + category.AttributeExtensions.Add(new XmlQualifiedName(prefix + "category_name1"), null); + category.AttributeExtensions.Add(new XmlQualifiedName(prefix + "category_name2", prefix + "category_namespace"), ""); + category.AttributeExtensions.Add(new XmlQualifiedName(prefix + "category_name3", prefix + "category_namespace"), prefix + "category_value"); + category.AttributeExtensions.Add(new XmlQualifiedName(prefix + "category_name4", "xmlns"), ""); + + category.ElementExtensions.Add(new ExtensionObject { Value = 10 }); + + category.Label = prefix + "category_label"; + + category.Name = prefix + "category_name"; + + category.Scheme = prefix + "category_scheme"; + + return category; + } + + SyndicationLink CreateLink(string prefix) + { + var link = new SyndicationLink(); + link.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name1"), null); + link.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name2", prefix + "_namespace"), ""); + link.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name3", prefix + "_namespace"), prefix + "_value"); + link.AttributeExtensions.Add(new XmlQualifiedName(prefix + "_name4", "xmlns"), ""); + + link.BaseUri = new Uri("http://" + prefix + "_url.com"); + + link.ElementExtensions.Add(new ExtensionObject { Value = 10 }); + + link.Length = 10; + + link.MediaType = prefix + "_mediaType"; + + link.RelationshipType = prefix + "_relationshipType"; + + link.Title = prefix + "_title"; + + link.Uri = new Uri("http://" + prefix +"_uri.com"); + + return link; + } + + var attributeSyndicationCategory = new SyndicationCategory + { + Name = "name", + Label = "label", + Scheme = "scheme" + }; + attributeSyndicationCategory.AttributeExtensions.Add(new XmlQualifiedName("term"), "term_value"); + attributeSyndicationCategory.AttributeExtensions.Add(new XmlQualifiedName("label"), "label_value"); + attributeSyndicationCategory.AttributeExtensions.Add(new XmlQualifiedName("scheme"), "scheme_value"); + + var attributeSyndicationLink = new SyndicationLink + { + RelationshipType = "link_relationshipType", + MediaType = "link_mediaType", + Title = "link_title", + Length = 10, + Uri = new Uri("http://link_uri.com") + }; + attributeSyndicationLink.AttributeExtensions.Add(new XmlQualifiedName("rel"), "rel_value"); + attributeSyndicationLink.AttributeExtensions.Add(new XmlQualifiedName("type"), "type_value"); + attributeSyndicationLink.AttributeExtensions.Add(new XmlQualifiedName("title"), "title_value"); + attributeSyndicationLink.AttributeExtensions.Add(new XmlQualifiedName("length"), "100"); + attributeSyndicationLink.AttributeExtensions.Add(new XmlQualifiedName("href"), "href_value"); + + var fullSyndicationItem = new SyndicationItem(); + fullSyndicationItem.AttributeExtensions.Add(new XmlQualifiedName("item_name1"), null); + fullSyndicationItem.AttributeExtensions.Add(new XmlQualifiedName("item_name2", "item_namespace"), ""); + fullSyndicationItem.AttributeExtensions.Add(new XmlQualifiedName("item_name3", "item_namespace"), "item_value"); + fullSyndicationItem.AttributeExtensions.Add(new XmlQualifiedName("item_name4", "xmlns"), ""); + + fullSyndicationItem.Authors.Add(new SyndicationPerson()); + fullSyndicationItem.Authors.Add(CreatePerson("author")); + + fullSyndicationItem.BaseUri = new Uri("http://microsoft/relative"); + + fullSyndicationItem.Categories.Add(new SyndicationCategory()); + fullSyndicationItem.Categories.Add(CreateCategory("")); + fullSyndicationItem.Categories.Add(attributeSyndicationCategory); + + fullSyndicationItem.Content = CreateContent("content"); + + fullSyndicationItem.Contributors.Add(new SyndicationPerson()); + fullSyndicationItem.Contributors.Add(CreatePerson("contributor")); + + fullSyndicationItem.Copyright = CreateContent("copyright"); + + fullSyndicationItem.ElementExtensions.Add(new ExtensionObject { Value = 10 }); + + fullSyndicationItem.Id = "id"; + + fullSyndicationItem.LastUpdatedTime = DateTimeOffset.MinValue.AddTicks(100); + + fullSyndicationItem.Links.Add(new SyndicationLink()); + fullSyndicationItem.Links.Add(CreateLink("link")); + fullSyndicationItem.Links.Add(attributeSyndicationLink); + + fullSyndicationItem.PublishDate = DateTimeOffset.MinValue.AddTicks(200); + + fullSyndicationItem.Summary = CreateContent("summary"); + + fullSyndicationItem.Title = CreateContent("title"); + + var fullSyndicationFeed = new SyndicationFeed(); + + fullSyndicationFeed.AttributeExtensions.Add(new XmlQualifiedName("feed_name1"), null); + fullSyndicationFeed.AttributeExtensions.Add(new XmlQualifiedName("feed_name2", "feed_namespace"), ""); + fullSyndicationFeed.AttributeExtensions.Add(new XmlQualifiedName("feed_name3", "feed_namespace"), "feed_value"); + fullSyndicationFeed.AttributeExtensions.Add(new XmlQualifiedName("feed_name4", "xmlns"), ""); + + fullSyndicationFeed.Authors.Add(new SyndicationPerson()); + fullSyndicationFeed.Authors.Add(CreatePerson("feedauthor")); + + fullSyndicationFeed.BaseUri = new Uri("http://microsoft.com"); + + fullSyndicationFeed.Categories.Add(new SyndicationCategory()); + fullSyndicationFeed.Categories.Add(CreateCategory("feed")); + fullSyndicationItem.Categories.Add(attributeSyndicationCategory); + + fullSyndicationFeed.Contributors.Add(new SyndicationPerson()); + fullSyndicationFeed.Contributors.Add(CreatePerson("feedauthor_")); + + fullSyndicationFeed.Copyright = CreateContent("feedcopyright"); + + fullSyndicationFeed.Description = CreateContent("feeddescription"); + + fullSyndicationFeed.ElementExtensions.Add(new ExtensionObject { Value = 10 }); + + fullSyndicationFeed.Generator = "generator"; + + fullSyndicationFeed.Id = "id"; + + fullSyndicationFeed.ImageUrl = new Uri("http://imageurl.com"); + + fullSyndicationFeed.Items = new SyndicationItem[] { new SyndicationItem() { Id = "id", LastUpdatedTime = DateTimeOffset.MinValue.AddTicks(1) }, fullSyndicationItem }; + + fullSyndicationFeed.Language = "language"; + + fullSyndicationFeed.LastUpdatedTime = DateTimeOffset.MinValue.AddYears(1); + + fullSyndicationFeed.Links.Add(new SyndicationLink()); + fullSyndicationFeed.Links.Add(CreateLink("syndicationlink")); + fullSyndicationFeed.Links.Add(attributeSyndicationLink); + + fullSyndicationFeed.Title = CreateContent("feedtitle"); + + foreach (bool serializeExtensionsAsAtom in new bool[] { true, false }) + { + yield return new object[] + { + fullSyndicationFeed, + serializeExtensionsAsAtom, +@" <channel xml:base=""http://microsoft.com/"" feed_name1="""" d2p1:feed_name2="""" d2p1:feed_name3=""feed_value"" d2p2:feed_name4="""" xmlns:d2p2=""xmlns"" xmlns:d2p1=""feed_namespace""> + <title>feedtitle_title + feeddescription_title + language + feedcopyright_title + + + feedauthor_name + feedauthor_uri + feedauthor_email + + 10 + + + Tue, 01 Jan 0002 00:00:00 Z + + feedcategory_name + generator + + + feedauthor__name + feedauthor__uri + feedauthor__email + + 10 + + + + http://imageurl.com/ + feedtitle_title + + + id + + + + 10 + + + + + 10 + + + id + + 0001-01-01T00:00:00Z + + + id + + + author_name + author_uri + author_email + + 10 + + + + category_name + name + name + title_title + summary_title + Mon, 01 Jan 0001 00:00:00 Z + + + + 10 + + + + 0001-01-01T00:00:00Z + copyright_title + content_title + + + contributor_name + contributor_uri + contributor_email + + 10 + + + + 10 + + + " + }; + } + } + + [Theory] + [MemberData(nameof(WriteTo_TestData))] + public void Write_HasFeed_SerializesExpected(SyndicationFeed feed, bool serializeExtensionsAsAtom, string expected) + { + var formatter = new Rss20FeedFormatter(feed); + string expectedFull = @"" + Environment.NewLine + expected + Environment.NewLine + ""; + string expectedSerializable = @"" + Environment.NewLine + expected + Environment.NewLine + ""; + + CompareHelper.AssertEqualWriteOutput(expectedFull, writer => formatter.WriteTo(writer)); + CompareHelper.AssertEqualWriteOutput(expectedFull, writer => feed.SaveAsRss20(writer)); + CompareHelper.AssertEqualWriteOutput(expectedSerializable, writer => + { + writer.WriteStartElement("feed"); + ((IXmlSerializable)formatter).WriteXml(writer); + writer.WriteEndElement(); + }); + + var genericFormatter = new Rss20FeedFormatter(feed); + CompareHelper.AssertEqualWriteOutput(expectedFull, writer => formatter.WriteTo(writer)); + CompareHelper.AssertEqualWriteOutput(expectedFull, writer => feed.SaveAsRss20(writer)); + } + + [Fact] + public void WriteTo_NullWriter_ThrowsArgumentNullException() + { + var formatter = new Rss20FeedFormatter(new SyndicationFeed()); + AssertExtensions.Throws("writer", () => formatter.WriteTo(null)); + } + + [Fact] + public void WriteTo_NoItem_ThrowsInvalidOperationException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.WriteTo(writer)); + } + } + + [Fact] + public void WriteXml_NullWriter_ThrowsArgumentNullException() + { + IXmlSerializable formatter = new Rss20FeedFormatter(); + AssertExtensions.Throws("writer", () => formatter.WriteXml(null)); + } + + [Fact] + public void WriteXml_NoItem_ThrowsInvalidOperationException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + IXmlSerializable formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.WriteXml(writer)); + } + } + + public static IEnumerable FeedBaseUri_TestData() + { + yield return new object[] { null }; + yield return new object[] { new Uri("http://microsoft.com") }; + yield return new object[] { new Uri("/relative", UriKind.Relative) }; + } + + [Theory] + [MemberData(nameof(FeedBaseUri_TestData))] + public void WriteItem_Invoke_Success(Uri feedBaseUri) + { + var formatter = new Formatter(); + var item = new SyndicationItem() { Id = "id", LastUpdatedTime = DateTimeOffset.MinValue.AddTicks(1) }; + CompareHelper.AssertEqualWriteOutput( +@" + id + + 0001-01-01T00:00:00Z +", writer => formatter.WriteItemEntryPoint(writer, item, feedBaseUri)); + } + + [Fact] + public void WriteItem_NullWriter_ThrowsNullReferenceException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + Assert.Throws(() => formatter.WriteItemEntryPoint(null, new SyndicationItem(), new Uri("http://microsoft.com"))); + } + } + + [Fact] + public void WriteItem_NullItem_ThrowsNullReferenceException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + Assert.Throws(() => formatter.WriteItemEntryPoint(writer, null, new Uri("http://microsoft.com"))); + } + } + + [Theory] + [MemberData(nameof(FeedBaseUri_TestData))] + public void WriteItems_Invoke_Success(Uri feedBaseUri) + { + var formatter = new Formatter(); + var items = new SyndicationItem[] + { + new SyndicationItem() { Id = "id1", LastUpdatedTime = DateTimeOffset.MinValue.AddTicks(1) }, + new SyndicationItem() { Id = "id2", LastUpdatedTime = DateTimeOffset.MinValue.AddTicks(1) } + }; + CompareHelper.AssertEqualWriteOutput( +@" + id1 + + 0001-01-01T00:00:00Z + + + id2 + + 0001-01-01T00:00:00Z +", writer => formatter.WriteItemsEntryPoint(writer, items, feedBaseUri)); + } + + [Fact] + public void WriteItems_NullItems_Nop() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + formatter.WriteItemsEntryPoint(writer, null, new Uri("http://microsoft.com")); + formatter.WriteItemsEntryPoint(null, null, new Uri("http://microsoft.com")); + } + } + + [Fact] + public void WriteItems_EmptyItems_Nop() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + formatter.WriteItemsEntryPoint(writer, new SyndicationItem[0], new Uri("http://microsoft.com")); + formatter.WriteItemsEntryPoint(null, new SyndicationItem[0], new Uri("http://microsoft.com")); + } + } + + [Fact] + public void WriteItems_NullWriter_ThrowsNullReferenceException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + var items = new SyndicationItem[] { new SyndicationItem() }; + Assert.Throws(() => formatter.WriteItemsEntryPoint(null, items, new Uri("http://microsoft.com"))); + } + } + + [Fact] + public void WriteItems_NullItemInItems_ThrowsNullReferenceException() + { + using (var stringWriter = new StringWriter()) + using (var writer = XmlWriter.Create(stringWriter)) + { + var formatter = new Formatter(); + var items = new SyndicationItem[] { null }; + Assert.Throws(() => formatter.WriteItemsEntryPoint(writer, items, new Uri("http://microsoft.com"))); + } + } + + public static IEnumerable CanRead_TestData() + { + yield return new object[] { @"", true }; + yield return new object[] { @"", false }; + yield return new object[] { @"", false }; + yield return new object[] { @"", true }; + yield return new object[] { @"", true }; + } + + [Theory] + [MemberData(nameof(CanRead_TestData))] + public void CanRead_ValidReader_ReturnsExpected(string xmlString, bool expected) + { + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter(); + Assert.Equal(expected, formatter.CanRead(reader)); + } + } + + [Fact] + public void CanRead_NullReader_ThrowsArgumentNullException() + { + var formatter = new Rss20FeedFormatter(); + AssertExtensions.Throws("reader", () => formatter.CanRead(null)); + } + + [Theory] + [InlineData(true, true)] + [InlineData(false, false)] + public void Read_FullItem_ReturnsExpected(bool preserveAttributeExtensions, bool preserveElementExtensions) + { + VerifyRead( +@" + + feedtitle_title + feeddescription_title + language + feedcopyright_title + + + feedauthor_name + feedauthor_uri + feedauthor_email + + 10 + + + Tue, 01 Jan 0002 00:00:00 Z + + feedcategory_name + generator + + + feedauthor__name + feedauthor__uri + feedauthor__email + + 10 + + + + http://imageurl.com/ + feedtitle_title + + + id + + + + 10 + + + + + 10 + + + id + + 0001-01-01T00:00:00Z + + + id + + + author_name + author_uri + author_email + + 10 + + + + category_name + name + name + title_title + summary_title + Mon, 01 Jan 0001 00:00:00 Z + + + + 10 + + + + 0001-01-01T00:00:00Z + copyright_title + content_title + + + contributor_name + contributor_uri + contributor_email + + 10 + + + + 10 + + + +", preserveAttributeExtensions, preserveElementExtensions, feed => + { + if (preserveAttributeExtensions) + { + Assert.Equal(4, feed.AttributeExtensions.Count); + Assert.Equal(4, feed.AttributeExtensions.Count); + Assert.Equal("", feed.AttributeExtensions[new XmlQualifiedName("feed_name1")]); + Assert.Equal("", feed.AttributeExtensions[new XmlQualifiedName("feed_name2", "feed_namespace")]); + Assert.Equal("feed_value", feed.AttributeExtensions[new XmlQualifiedName("feed_name3", "feed_namespace")]); + Assert.Equal("", feed.AttributeExtensions[new XmlQualifiedName("feed_name4", "xmlns")]); + } + else + { + Assert.Empty(feed.AttributeExtensions); + } + + Assert.Equal(2, feed.Authors.Count); + + SyndicationPerson firstAuthor = feed.Authors[0]; + Assert.Empty(firstAuthor.AttributeExtensions); + Assert.Empty(firstAuthor.ElementExtensions); + Assert.Null(firstAuthor.Email); + Assert.Null(firstAuthor.Name); + Assert.Null(firstAuthor.Uri); + + SyndicationPerson secondAuthor = feed.Authors[1]; + Assert.Equal(4, secondAuthor.AttributeExtensions.Count); + Assert.Equal(4, secondAuthor.AttributeExtensions.Count); + Assert.Equal("", secondAuthor.AttributeExtensions[new XmlQualifiedName("feedauthor_name1")]); + Assert.Equal("", secondAuthor.AttributeExtensions[new XmlQualifiedName("feedauthor_name2", "feedauthor_namespace")]); + Assert.Equal("feedauthor_value", secondAuthor.AttributeExtensions[new XmlQualifiedName("feedauthor_name3", "feedauthor_namespace")]); + Assert.Equal("", secondAuthor.AttributeExtensions[new XmlQualifiedName("feedauthor_name4", "xmlns")]); + Assert.Equal(1, secondAuthor.ElementExtensions.Count()); + Assert.Equal("feedauthor_email", secondAuthor.Email); + Assert.Equal("feedauthor_name", secondAuthor.Name); + Assert.Equal("feedauthor_uri", secondAuthor.Uri); + + Assert.Equal(new Uri("http://microsoft.com"), feed.BaseUri); + + Assert.Equal(2, feed.Categories.Count); + SyndicationCategory firstCategory = feed.Categories[0]; + Assert.Empty(firstCategory.AttributeExtensions); + Assert.Empty(firstCategory.ElementExtensions); + Assert.Null(firstCategory.Name); + Assert.Null(firstCategory.Scheme); + Assert.Null(firstCategory.Label); + + SyndicationCategory secondCategory = feed.Categories[1]; + if (preserveAttributeExtensions) + { + Assert.Equal(4, secondCategory.AttributeExtensions.Count); + Assert.Equal(4, secondCategory.AttributeExtensions.Count); + Assert.Equal("", secondCategory.AttributeExtensions[new XmlQualifiedName("feedcategory_name1")]); + Assert.Equal("", secondCategory.AttributeExtensions[new XmlQualifiedName("feedcategory_name2", "feedcategory_namespace")]); + Assert.Equal("feedcategory_value", secondCategory.AttributeExtensions[new XmlQualifiedName("feedcategory_name3", "feedcategory_namespace")]); + Assert.Equal("", secondCategory.AttributeExtensions[new XmlQualifiedName("feedcategory_name4", "xmlns")]); + } + else + { + Assert.Empty(secondCategory.AttributeExtensions); + } + Assert.Empty(secondCategory.ElementExtensions); + Assert.Equal("feedcategory_name", secondCategory.Name); + Assert.Equal("feedcategory_scheme", secondCategory.Scheme); + Assert.Null(secondCategory.Label); + + Assert.Equal(2, feed.Contributors.Count); + SyndicationPerson firstContributor = feed.Contributors[0]; + Assert.Empty(firstContributor.AttributeExtensions); + Assert.Empty(firstContributor.ElementExtensions); + Assert.Null(firstContributor.Email); + Assert.Null(firstContributor.Name); + Assert.Null(firstContributor.Uri); + + SyndicationPerson secondContributor = feed.Contributors[1]; + Assert.Equal(4, secondContributor.AttributeExtensions.Count); + Assert.Equal(4, secondContributor.AttributeExtensions.Count); + Assert.Equal("", secondContributor.AttributeExtensions[new XmlQualifiedName("feedauthor__name1")]); + Assert.Equal("", secondContributor.AttributeExtensions[new XmlQualifiedName("feedauthor__name2", "feedauthor__namespace")]); + Assert.Equal("feedauthor__value", secondContributor.AttributeExtensions[new XmlQualifiedName("feedauthor__name3", "feedauthor__namespace")]); + Assert.Equal("", secondContributor.AttributeExtensions[new XmlQualifiedName("feedauthor__name4", "xmlns")]); + Assert.Equal(1, secondContributor.ElementExtensions.Count()); + Assert.Equal("feedauthor__email", secondContributor.Email); + Assert.Equal("feedauthor__name", secondContributor.Name); + Assert.Equal("feedauthor__uri", secondContributor.Uri); + + Assert.Empty(feed.Copyright.AttributeExtensions); + Assert.Equal("feedcopyright_title", feed.Copyright.Text); + Assert.Equal("text", feed.Copyright.Type); + + Assert.Equal("generator", feed.Generator); + + if (preserveElementExtensions) + { + Assert.Equal(1, feed.ElementExtensions.Count()); + } + else + { + Assert.Empty(feed.ElementExtensions); + } + + Assert.Equal("id", feed.Id); + + Assert.Equal(new Uri("http://imageurl.com/"), feed.ImageUrl); + + SyndicationItem[] items = feed.Items.ToArray(); + Assert.Equal(2, items.Length); + + SyndicationItem item = items[1]; + + if (preserveAttributeExtensions) + { + Assert.Equal(4, item.AttributeExtensions.Count); + Assert.Equal(4, item.AttributeExtensions.Count); + Assert.Equal("", item.AttributeExtensions[new XmlQualifiedName("item_name1")]); + Assert.Equal("", item.AttributeExtensions[new XmlQualifiedName("item_name2", "item_namespace")]); + Assert.Equal("item_value", item.AttributeExtensions[new XmlQualifiedName("item_name3", "item_namespace")]); + Assert.Equal("", item.AttributeExtensions[new XmlQualifiedName("item_name4", "xmlns")]); + } + else + { + Assert.Empty(item.AttributeExtensions); + } + if (preserveElementExtensions) + { + Assert.Equal(1, item.ElementExtensions.Count()); + } + else + { + Assert.Empty(item.ElementExtensions); + } + + Assert.Equal(2, item.Authors.Count); + + SyndicationPerson itemFirstAuthor = item.Authors[0]; + Assert.Empty(itemFirstAuthor.AttributeExtensions); + Assert.Empty(itemFirstAuthor.ElementExtensions); + Assert.Null(itemFirstAuthor.Email); + Assert.Null(itemFirstAuthor.Name); + Assert.Null(itemFirstAuthor.Uri); + + SyndicationPerson itemSecondAuthor = item.Authors[1]; + + Assert.Equal(4, itemSecondAuthor.AttributeExtensions.Count); + Assert.Equal(4, itemSecondAuthor.AttributeExtensions.Count); + Assert.Equal("", itemSecondAuthor.AttributeExtensions[new XmlQualifiedName("author_name1")]); + Assert.Equal("", itemSecondAuthor.AttributeExtensions[new XmlQualifiedName("author_name2", "author_namespace")]); + Assert.Equal("author_value", itemSecondAuthor.AttributeExtensions[new XmlQualifiedName("author_name3", "author_namespace")]); + Assert.Equal("", itemSecondAuthor.AttributeExtensions[new XmlQualifiedName("author_name4", "xmlns")]); + Assert.Equal(1, itemSecondAuthor.ElementExtensions.Count()); + Assert.Equal("author_email", itemSecondAuthor.Email); + Assert.Equal("author_name", itemSecondAuthor.Name); + Assert.Equal("author_uri", itemSecondAuthor.Uri); + + Assert.Equal(new Uri("http://microsoft/relative"), item.BaseUri); + + Assert.Equal(4, item.Categories.Count); + SyndicationCategory itemFirstCategory = item.Categories[0]; + Assert.Empty(itemFirstCategory.AttributeExtensions); + Assert.Empty(itemFirstCategory.ElementExtensions); + Assert.Null(itemFirstCategory.Name); + Assert.Null(itemFirstCategory.Scheme); + Assert.Null(itemFirstCategory.Label); + + SyndicationCategory itemSecondCategory = item.Categories[1]; + + if (preserveAttributeExtensions) + { + Assert.Equal(4, itemSecondCategory.AttributeExtensions.Count); + Assert.Equal(4, itemSecondCategory.AttributeExtensions.Count); + Assert.Equal("", itemSecondCategory.AttributeExtensions[new XmlQualifiedName("category_name1")]); + Assert.Equal("", itemSecondCategory.AttributeExtensions[new XmlQualifiedName("category_name2", "category_namespace")]); + Assert.Equal("category_value", itemSecondCategory.AttributeExtensions[new XmlQualifiedName("category_name3", "category_namespace")]); + Assert.Equal("", itemSecondCategory.AttributeExtensions[new XmlQualifiedName("category_name4", "xmlns")]); + } + else + { + Assert.Empty(itemSecondCategory.AttributeExtensions); + } + Assert.Empty(itemSecondCategory.ElementExtensions); + Assert.Equal("category_name", itemSecondCategory.Name); + Assert.Equal("category_scheme", itemSecondCategory.Scheme); + Assert.Null(itemSecondCategory.Label); + + SyndicationCategory itemThirdCategory = item.Categories[2]; + if (preserveAttributeExtensions) + { + Assert.Equal(3, itemThirdCategory.AttributeExtensions.Count); + Assert.Equal("term_value", itemThirdCategory.AttributeExtensions[new XmlQualifiedName("term")]); + Assert.Equal("label_value", itemThirdCategory.AttributeExtensions[new XmlQualifiedName("label")]); + Assert.Equal("scheme_value", itemThirdCategory.AttributeExtensions[new XmlQualifiedName("scheme")]); + } + else + { + Assert.Empty(itemThirdCategory.AttributeExtensions); + } + Assert.Empty(itemThirdCategory.ElementExtensions); + Assert.Equal("name", itemThirdCategory.Name); + Assert.Equal("scheme", itemThirdCategory.Scheme); + Assert.Null(itemThirdCategory.Label); + + SyndicationCategory itemFourthCategory = item.Categories[3]; + if (preserveAttributeExtensions) + { + Assert.Equal(3, itemFourthCategory.AttributeExtensions.Count); + Assert.Equal("term_value", itemFourthCategory.AttributeExtensions[new XmlQualifiedName("term")]); + Assert.Equal("label_value", itemFourthCategory.AttributeExtensions[new XmlQualifiedName("label")]); + Assert.Equal("scheme_value", itemFourthCategory.AttributeExtensions[new XmlQualifiedName("scheme")]); + } + else + { + Assert.Empty(itemFourthCategory.AttributeExtensions); + } + Assert.Empty(itemFourthCategory.ElementExtensions); + Assert.Equal("name", itemFourthCategory.Name); + Assert.Equal("scheme", itemFourthCategory.Scheme); + Assert.Null(itemFourthCategory.Label); + + TextSyndicationContent content = Assert.IsType(item.Content); + + Assert.Equal(4, content.AttributeExtensions.Count); + Assert.Equal(4, content.AttributeExtensions.Count); + Assert.Equal("", content.AttributeExtensions[new XmlQualifiedName("content_name1")]); + Assert.Equal("", content.AttributeExtensions[new XmlQualifiedName("content_name2", "content_namespace")]); + Assert.Equal("content_value", content.AttributeExtensions[new XmlQualifiedName("content_name3", "content_namespace")]); + Assert.Equal("", content.AttributeExtensions[new XmlQualifiedName("content_name4", "xmlns")]); + Assert.Equal("content_title", content.Text); + Assert.Equal("html", content.Type); + + Assert.Equal(2, item.Contributors.Count); + + SyndicationPerson itemFirstContributor = item.Contributors[0]; + Assert.Empty(itemFirstContributor.AttributeExtensions); + Assert.Empty(itemFirstContributor.ElementExtensions); + Assert.Null(itemFirstContributor.Email); + Assert.Null(itemFirstContributor.Name); + Assert.Null(itemFirstContributor.Uri); + + SyndicationPerson itemSecondContributor = item.Contributors[1]; + Assert.Equal(4, itemSecondContributor.AttributeExtensions.Count); + Assert.Equal("", itemSecondContributor.AttributeExtensions[new XmlQualifiedName("contributor_name1")]); + Assert.Equal("", itemSecondContributor.AttributeExtensions[new XmlQualifiedName("contributor_name2", "contributor_namespace")]); + Assert.Equal("contributor_value", itemSecondContributor.AttributeExtensions[new XmlQualifiedName("contributor_name3", "contributor_namespace")]); + Assert.Equal("", itemSecondContributor.AttributeExtensions[new XmlQualifiedName("contributor_name4", "xmlns")]); + Assert.Equal(1, itemSecondContributor.ElementExtensions.Count()); + Assert.Equal("contributor_email", itemSecondContributor.Email); + Assert.Equal("contributor_name", itemSecondContributor.Name); + Assert.Equal("contributor_uri", itemSecondContributor.Uri); + + Assert.Equal(4, item.Copyright.AttributeExtensions.Count); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name1")]); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name2", "copyright_namespace")]); + Assert.Equal("copyright_value", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name3", "copyright_namespace")]); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name4", "xmlns")]); + Assert.Equal("copyright_title", item.Copyright.Text); + Assert.Equal("html", item.Copyright.Type); + + if (preserveElementExtensions) + { + Assert.Equal(1, item.ElementExtensions.Count()); + } + else + { + Assert.Empty(item.ElementExtensions); + } + + Assert.Equal("id", item.Id); + + Assert.Equal(DateTimeOffset.MinValue, item.LastUpdatedTime); + + Assert.Equal(3, item.Links.Count); + + SyndicationLink itemFirstLink = item.Links[0]; + Assert.Empty(itemFirstLink.AttributeExtensions); + Assert.Empty(itemFirstLink.ElementExtensions); + Assert.Equal(0, itemFirstLink.Length); + Assert.Null(itemFirstLink.MediaType); + Assert.Null(itemFirstLink.RelationshipType); + Assert.Null(itemFirstLink.Title); + Assert.Equal(string.Empty, itemFirstLink.Uri.OriginalString); + + SyndicationLink itemSecondLink = item.Links[1]; + Assert.Equal(4, itemSecondLink.AttributeExtensions.Count); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name1")]); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name2", "link_namespace")]); + Assert.Equal("link_value", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name3", "link_namespace")]); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name4", "xmlns")]); + Assert.Equal(1, itemSecondLink.ElementExtensions.Count()); + Assert.Equal(new Uri("http://link_url.com"), itemSecondLink.BaseUri); + Assert.Equal(10, itemSecondLink.Length); + Assert.Equal("link_mediaType", itemSecondLink.MediaType); + Assert.Equal("link_relationshipType", itemSecondLink.RelationshipType); + Assert.Equal("link_title", itemSecondLink.Title); + Assert.Equal(new Uri("http://link_uri.com"), itemSecondLink.Uri); + + SyndicationLink itemThirdLink = item.Links[2]; + Assert.Empty(itemThirdLink.AttributeExtensions); + Assert.Empty(itemThirdLink.ElementExtensions); + Assert.Equal(100, itemThirdLink.Length); + Assert.Equal("type_value", itemThirdLink.MediaType); + Assert.Equal("rel_value", itemThirdLink.RelationshipType); + Assert.Equal("title_value", itemThirdLink.Title); + Assert.Equal("href_value", itemThirdLink.Uri.OriginalString); + + Assert.Equal(DateTimeOffset.MinValue, item.PublishDate); + + Assert.Null(item.SourceFeed); + + Assert.Empty(item.Summary.AttributeExtensions); + Assert.Equal("summary_title", item.Summary.Text); + Assert.Equal("text", item.Summary.Type); + + Assert.Empty(item.Title.AttributeExtensions); + Assert.Equal("title_title", item.Title.Text); + Assert.Equal("text", item.Title.Type); + + Assert.Equal("language", feed.Language); + + Assert.Equal(DateTimeOffset.MinValue.AddYears(1), feed.LastUpdatedTime); + Assert.Equal(3, feed.Links.Count); + + SyndicationLink firstLink = feed.Links[0]; + Assert.Empty(firstLink.AttributeExtensions); + Assert.Empty(firstLink.ElementExtensions); + Assert.Equal(0, firstLink.Length); + Assert.Null(firstLink.MediaType); + Assert.Null(firstLink.RelationshipType); + Assert.Null(firstLink.Title); + Assert.Equal("", firstLink.Uri.OriginalString); + + SyndicationLink secondLink = feed.Links[1]; + Assert.Equal(4, secondLink.AttributeExtensions.Count); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name1")]); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name2", "syndicationlink_namespace")]); + Assert.Equal("syndicationlink_value", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name3", "syndicationlink_namespace")]); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name4", "xmlns")]); + Assert.Equal(1, secondLink.ElementExtensions.Count()); + Assert.Equal(new Uri("http://syndicationlink_url.com/"), secondLink.BaseUri); + Assert.Equal(10, secondLink.Length); + Assert.Equal("syndicationlink_mediaType", secondLink.MediaType); + Assert.Equal("syndicationlink_relationshipType", secondLink.RelationshipType); + Assert.Equal("syndicationlink_title", secondLink.Title); + Assert.Equal("http://syndicationlink_uri.com/", secondLink.Uri.OriginalString); + + SyndicationLink thirdLink = feed.Links[2]; + Assert.Empty(thirdLink.AttributeExtensions); + Assert.Empty(thirdLink.ElementExtensions); + Assert.Equal(100, thirdLink.Length); + Assert.Equal("type_value", thirdLink.MediaType); + Assert.Equal("rel_value", thirdLink.RelationshipType); + Assert.Equal("title_value", thirdLink.Title); + Assert.Equal("href_value", thirdLink.Uri.OriginalString); + + Assert.Empty(item.Title.AttributeExtensions); + Assert.Equal("feedtitle_title", feed.Title.Text); + Assert.Equal("text", feed.Title.Type); + }); + } + + [Theory] + [InlineData(true, true)] + [InlineData(false, false)] + public void Read_TryParseTrue_ReturnsExpected(bool preserveAttributeExtensions, bool preserveElementExtensions) + { + using (var stringReader = new StringReader( +@" + + feedtitle_title + feeddescription_title + language + feedcopyright_title + + + feedauthor_name + feedauthor_uri + feedauthor_email + + 10 + + + Tue, 01 Jan 0002 00:00:00 Z + + feedcategory_name + generator + + + feedauthor__name + feedauthor__uri + feedauthor__email + + 10 + + + + http://imageurl.com/ + feedtitle_title + + + id + + + + 10 + + + + + 10 + + + id + + 0001-01-01T00:00:00Z + + + id + + + author_name + author_uri + author_email + + 10 + + + + category_name + name + name + title_title + summary_title + Mon, 01 Jan 0001 00:00:00 Z + + + + 10 + + + + 0001-01-01T00:00:00Z + copyright_title + content_title + + + contributor_name + contributor_uri + contributor_email + + 10 + + + + 10 + + + +")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + + SyndicationFeed feed = formatter.Feed; + Assert.Empty(feed.AttributeExtensions); + + Assert.Equal(2, feed.Authors.Count); + + SyndicationPerson firstAuthor = feed.Authors[0]; + Assert.Empty(firstAuthor.AttributeExtensions); + Assert.Empty(firstAuthor.ElementExtensions); + Assert.Null(firstAuthor.Email); + Assert.Null(firstAuthor.Name); + Assert.Null(firstAuthor.Uri); + + SyndicationPerson secondAuthor = feed.Authors[1]; + Assert.Empty(secondAuthor.AttributeExtensions); + Assert.Empty(secondAuthor.ElementExtensions); + Assert.Equal("feedauthor_email", secondAuthor.Email); + Assert.Equal("feedauthor_name", secondAuthor.Name); + Assert.Equal("feedauthor_uri", secondAuthor.Uri); + + Assert.Equal(new Uri("http://microsoft.com"), feed.BaseUri); + + Assert.Equal(2, feed.Categories.Count); + SyndicationCategory firstCategory = feed.Categories[0]; + Assert.Empty(firstCategory.AttributeExtensions); + Assert.Empty(firstCategory.ElementExtensions); + Assert.Null(firstCategory.Name); + Assert.Null(firstCategory.Scheme); + Assert.Null(firstCategory.Label); + + SyndicationCategory secondCategory = feed.Categories[1]; + Assert.Empty(secondCategory.AttributeExtensions); + Assert.Empty(secondCategory.ElementExtensions); + Assert.Equal("feedcategory_name", secondCategory.Name); + Assert.Equal("feedcategory_scheme", secondCategory.Scheme); + Assert.Null(secondCategory.Label); + + Assert.Equal(2, feed.Contributors.Count); + SyndicationPerson firstContributor = feed.Contributors[0]; + Assert.Empty(firstContributor.AttributeExtensions); + Assert.Empty(firstContributor.ElementExtensions); + Assert.Null(firstContributor.Email); + Assert.Null(firstContributor.Name); + Assert.Null(firstContributor.Uri); + + SyndicationPerson secondContributor = feed.Contributors[1]; + Assert.Empty(secondContributor.AttributeExtensions); + Assert.Empty(secondContributor.ElementExtensions); + Assert.Equal("feedauthor__email", secondContributor.Email); + Assert.Equal("feedauthor__name", secondContributor.Name); + Assert.Equal("feedauthor__uri", secondContributor.Uri); + + Assert.Empty(feed.Copyright.AttributeExtensions); + Assert.Equal("feedcopyright_title", feed.Copyright.Text); + Assert.Equal("text", feed.Copyright.Type); + + Assert.Equal("generator", feed.Generator); + + Assert.Empty(feed.ElementExtensions); + + Assert.Equal("id", feed.Id); + + Assert.Equal(new Uri("http://imageurl.com/"), feed.ImageUrl); + + SyndicationItem[] items = feed.Items.ToArray(); + Assert.Equal(2, items.Length); + + SyndicationItem item = items[1]; + Assert.Empty(item.AttributeExtensions); + + Assert.Equal(2, item.Authors.Count); + + SyndicationPerson itemFirstAuthor = item.Authors[0]; + Assert.Empty(itemFirstAuthor.AttributeExtensions); + Assert.Empty(itemFirstAuthor.ElementExtensions); + Assert.Null(itemFirstAuthor.Email); + Assert.Null(itemFirstAuthor.Name); + Assert.Null(itemFirstAuthor.Uri); + + SyndicationPerson itemSecondAuthor = item.Authors[1]; + Assert.Empty(itemSecondAuthor.AttributeExtensions); + Assert.Empty(itemSecondAuthor.ElementExtensions); + Assert.Equal("author_email", itemSecondAuthor.Email); + Assert.Equal("author_name", itemSecondAuthor.Name); + Assert.Equal("author_uri", itemSecondAuthor.Uri); + + Assert.Equal(new Uri("http://microsoft/relative"), item.BaseUri); + + Assert.Equal(4, item.Categories.Count); + SyndicationCategory itemFirstCategory = item.Categories[0]; + Assert.Empty(itemFirstCategory.AttributeExtensions); + Assert.Empty(itemFirstCategory.ElementExtensions); + Assert.Null(itemFirstCategory.Name); + Assert.Null(itemFirstCategory.Scheme); + Assert.Null(itemFirstCategory.Label); + + SyndicationCategory itemSecondCategory = item.Categories[1]; + Assert.Empty(itemSecondCategory.AttributeExtensions); + Assert.Empty(itemSecondCategory.ElementExtensions); + Assert.Equal("category_name", itemSecondCategory.Name); + Assert.Equal("category_scheme", itemSecondCategory.Scheme); + Assert.Null(itemSecondCategory.Label); + + SyndicationCategory itemThirdCategory = item.Categories[2]; + Assert.Empty(itemThirdCategory.AttributeExtensions); + Assert.Empty(itemThirdCategory.ElementExtensions); + Assert.Equal("name", itemThirdCategory.Name); + Assert.Equal("scheme", itemThirdCategory.Scheme); + Assert.Null(itemThirdCategory.Label); + + SyndicationCategory itemFourthCategory = item.Categories[3]; + Assert.Empty(itemFourthCategory.AttributeExtensions); + Assert.Empty(itemFourthCategory.ElementExtensions); + Assert.Equal("name", itemFourthCategory.Name); + Assert.Equal("scheme", itemFourthCategory.Scheme); + Assert.Null(itemFourthCategory.Label); + + TextSyndicationContent content = Assert.IsType(item.Content); + Assert.Empty(content.AttributeExtensions); + Assert.Equal("overriden", content.Text); + Assert.Equal("text", content.Type); + + Assert.Equal(2, item.Contributors.Count); + + SyndicationPerson itemFirstContributor = item.Contributors[0]; + Assert.Empty(itemFirstContributor.AttributeExtensions); + Assert.Empty(itemFirstContributor.ElementExtensions); + Assert.Null(itemFirstContributor.Email); + Assert.Null(itemFirstContributor.Name); + Assert.Null(itemFirstContributor.Uri); + + SyndicationPerson itemSecondContributor = item.Contributors[1]; + Assert.Empty(itemSecondContributor.AttributeExtensions); + Assert.Empty(itemSecondContributor.ElementExtensions); + Assert.Equal("contributor_email", itemSecondContributor.Email); + Assert.Equal("contributor_name", itemSecondContributor.Name); + Assert.Equal("contributor_uri", itemSecondContributor.Uri); + + Assert.Equal(4, item.Copyright.AttributeExtensions.Count); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name1")]); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name2", "copyright_namespace")]); + Assert.Equal("copyright_value", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name3", "copyright_namespace")]); + Assert.Equal("", item.Copyright.AttributeExtensions[new XmlQualifiedName("copyright_name4", "xmlns")]); + Assert.Equal("copyright_title", item.Copyright.Text); + Assert.Equal("html", item.Copyright.Type); + + Assert.Empty(item.ElementExtensions); + + Assert.Equal("id", item.Id); + + Assert.Equal(DateTimeOffset.MinValue, item.LastUpdatedTime); + + Assert.Equal(3, item.Links.Count); + + SyndicationLink itemFirstLink = item.Links[0]; + Assert.Empty(itemFirstLink.AttributeExtensions); + Assert.Empty(itemFirstLink.ElementExtensions); + Assert.Equal(0, itemFirstLink.Length); + Assert.Null(itemFirstLink.MediaType); + Assert.Null(itemFirstLink.RelationshipType); + Assert.Null(itemFirstLink.Title); + Assert.Equal(string.Empty, itemFirstLink.Uri.OriginalString); + + SyndicationLink itemSecondLink = item.Links[1]; + Assert.Equal(4, itemSecondLink.AttributeExtensions.Count); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name1")]); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name2", "link_namespace")]); + Assert.Equal("link_value", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name3", "link_namespace")]); + Assert.Equal("", itemSecondLink.AttributeExtensions[new XmlQualifiedName("link_name4", "xmlns")]); + Assert.Empty(itemSecondLink.ElementExtensions); + Assert.Equal(new Uri("http://link_url.com"), itemSecondLink.BaseUri); + Assert.Equal(10, itemSecondLink.Length); + Assert.Equal("link_mediaType", itemSecondLink.MediaType); + Assert.Equal("link_relationshipType", itemSecondLink.RelationshipType); + Assert.Equal("link_title", itemSecondLink.Title); + Assert.Equal(new Uri("http://link_uri.com"), itemSecondLink.Uri); + + SyndicationLink itemThirdLink = item.Links[2]; + Assert.Empty(itemThirdLink.AttributeExtensions); + Assert.Empty(itemThirdLink.ElementExtensions); + Assert.Equal(100, itemThirdLink.Length); + Assert.Equal("type_value", itemThirdLink.MediaType); + Assert.Equal("rel_value", itemThirdLink.RelationshipType); + Assert.Equal("title_value", itemThirdLink.Title); + Assert.Equal("href_value", itemThirdLink.Uri.OriginalString); + + Assert.Equal(DateTimeOffset.MinValue, item.PublishDate); + + Assert.Null(item.SourceFeed); + + Assert.Empty(item.Summary.AttributeExtensions); + Assert.Equal("summary_title", item.Summary.Text); + Assert.Equal("text", item.Summary.Type); + + Assert.Empty(item.Title.AttributeExtensions); + Assert.Equal("title_title", item.Title.Text); + Assert.Equal("text", item.Title.Type); + + Assert.Equal("language", feed.Language); + + Assert.Equal(DateTimeOffset.MinValue.AddYears(1), feed.LastUpdatedTime); + Assert.Equal(3, feed.Links.Count); + + SyndicationLink firstLink = feed.Links[0]; + Assert.Empty(firstLink.AttributeExtensions); + Assert.Empty(firstLink.ElementExtensions); + Assert.Equal(0, firstLink.Length); + Assert.Null(firstLink.MediaType); + Assert.Null(firstLink.RelationshipType); + Assert.Null(firstLink.Title); + Assert.Equal("", firstLink.Uri.OriginalString); + + SyndicationLink secondLink = feed.Links[1]; + Assert.Equal(4, secondLink.AttributeExtensions.Count); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name1")]); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name2", "syndicationlink_namespace")]); + Assert.Equal("syndicationlink_value", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name3", "syndicationlink_namespace")]); + Assert.Equal("", secondLink.AttributeExtensions[new XmlQualifiedName("syndicationlink_name4", "xmlns")]); + Assert.Empty(secondLink.ElementExtensions); + Assert.Equal(new Uri("http://syndicationlink_url.com/"), secondLink.BaseUri); + Assert.Equal(10, secondLink.Length); + Assert.Equal("syndicationlink_mediaType", secondLink.MediaType); + Assert.Equal("syndicationlink_relationshipType", secondLink.RelationshipType); + Assert.Equal("syndicationlink_title", secondLink.Title); + Assert.Equal("http://syndicationlink_uri.com/", secondLink.Uri.OriginalString); + + SyndicationLink thirdLink = feed.Links[2]; + Assert.Empty(thirdLink.AttributeExtensions); + Assert.Empty(thirdLink.ElementExtensions); + Assert.Equal(100, thirdLink.Length); + Assert.Equal("type_value", thirdLink.MediaType); + Assert.Equal("rel_value", thirdLink.RelationshipType); + Assert.Equal("title_value", thirdLink.Title); + Assert.Equal("href_value", thirdLink.Uri.OriginalString); + + Assert.Empty(item.Title.AttributeExtensions); + Assert.Equal("feedtitle_title", feed.Title.Text); + Assert.Equal("text", feed.Title.Type); + } + } + + [Theory] + [InlineData(true, true)] + [InlineData(false, false)] + public void Read_EmptyItem_ReturnsExpected(bool preserveAttributeExtensions, bool preserveElementExtensions) + { + VerifyRead(@"", preserveElementExtensions, preserveElementExtensions, feed => + { + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + }); + } + + private static void VerifyRead(string xmlString, bool preserveAttributeExtensions, bool preserveElementExtensions, Action verifyAction) + { + // ReadFrom. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + verifyAction(formatter.Feed); + } + + // ReadXml. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + ((IXmlSerializable)formatter).ReadXml(reader); + verifyAction(formatter.Feed); + } + + // Derived ReadFrom. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter(typeof(SyndicationFeedSubclass)) + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + verifyAction(formatter.Feed); + } + + // Derived ReadXml. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Rss20FeedFormatter(typeof(SyndicationFeedSubclass)) + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + ((IXmlSerializable)formatter).ReadXml(reader); + verifyAction(formatter.Feed); + } + + // Generic ReadFrom. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + verifyAction(formatter.Feed); + } + + // Generic ReadXml. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + ((IXmlSerializable)formatter).ReadXml(reader); + verifyAction(formatter.Feed); + } + + // Generic Derived ReadFrom. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + formatter.ReadFrom(reader); + verifyAction(formatter.Feed); + } + + // Generic Derived ReadXml. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Rss20FeedFormatter() + { + PreserveAttributeExtensions = preserveAttributeExtensions, + PreserveElementExtensions = preserveElementExtensions + }; + ((IXmlSerializable)formatter).ReadXml(reader); + verifyAction(formatter.Feed); + } + + if (preserveAttributeExtensions && preserveElementExtensions) + { + // Load. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + SyndicationFeed feed = SyndicationFeed.Load(reader); + verifyAction(feed); + } + + // Generic Load. + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + SyndicationFeed feed = SyndicationFeed.Load(reader); + verifyAction(feed); + } + } + } + + [Fact] + public void ReadFrom_NullReader_ThrowsArgumentNullException() + { + var formatter = new Rss20FeedFormatter(); + AssertExtensions.Throws("reader", () => formatter.ReadFrom(null)); + } + + [Fact] + public void ReadFrom_NullCreatedFeed_ThrowsArgumentNullException() + { + using (var stringReader = new StringReader(@"")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new NullCreatedFeedFormatter(); + AssertExtensions.Throws("feed", () => formatter.ReadFrom(reader)); + } + } + + [Theory] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + public void ReadFrom_CantRead_ThrowsXmlException(string xmlString) + { + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.ReadFrom(reader)); + } + } + + [Theory] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + public void ReadFrom_InvalidVersion_ThrowsNotSupportedException(string xmlString) + { + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.ReadFrom(reader)); + } + } + + [Theory] + [InlineData(@"")] + public void ReadXml_ValidReader_Success(string xmlString) + { + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Rss20FeedFormatter(); + ((IXmlSerializable)formatter).ReadXml(reader); + + SyndicationFeed feed = formatter.Feed; + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + } + } + + [Fact] + public void ReadXml_NullReader_ThrowsArgumentNullException() + { + IXmlSerializable formatter = new Rss20FeedFormatter(); + AssertExtensions.Throws("reader", () => formatter.ReadXml(null)); + } + + [Fact] + public void ReadXml_NullCreatedFeed_ThrowsArgumentNullException() + { + using (var stringReader = new StringReader(@"")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + IXmlSerializable formatter = new NullCreatedFeedFormatter(); + AssertExtensions.Throws("feed", () => formatter.ReadXml(reader)); + } + } + + [Theory] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + [InlineData(@"")] + public void ReadXml_CantRead_ThrowsXmlException(string xmlString) + { + using (var stringReader = new StringReader(xmlString)) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + IXmlSerializable formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.ReadXml(reader)); + } + } + + [Fact] + public void ReadXml_ThrowsArgumentException_RethrowsAsXmlException() + { + var reader = new ThrowingXmlReader(new ArgumentException()); + IXmlSerializable formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.ReadXml(reader)); + } + + [Fact] + public void ReadXml_ThrowsFormatException_RethrowsAsXmlException() + { + var reader = new ThrowingXmlReader(new FormatException()); + IXmlSerializable formatter = new Rss20FeedFormatter(); + Assert.Throws(() => formatter.ReadXml(reader)); + } + + [Fact] + public void ReadItem_ValidItem_ReturnsExpected() + { + using (var stringReader = new StringReader(@"id")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + + var formatter = new Formatter(); + var feed = new SyndicationFeed(); + SyndicationItem item = formatter.ReadItemEntryPoint(reader, feed); + Assert.Equal("id", item.Id); + Assert.Null(item.SourceFeed); + Assert.Empty(feed.Items); + } + } + + [Fact] + public void ReadItem_NullReader_ThrowsArgumentNullException() + { + var formatter = new Formatter(); + AssertExtensions.Throws("reader", () => formatter.ReadItemEntryPoint(null, new SyndicationFeed())); + } + + [Fact] + public void ReadItem_NullFeed_ThrowsArgumentNullException() + { + using (var stringReader = new StringReader("")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Formatter(); + AssertExtensions.Throws("feed", () => formatter.ReadItemEntryPoint(reader, null)); + } + } + + [Fact] + public void ReadItems_ValidItems_ReturnsExpected() + { + using (var stringReader = new StringReader( +@" + id1 + id2 + + id3 +")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + reader.MoveToContent(); + reader.ReadStartElement(); + reader.MoveToElement(); + + var formatter = new Formatter(); + var feed = new SyndicationFeed(); + SyndicationItem[] items = formatter.ReadItemsEntryPoint(reader, feed, out var areAllItemsRead).ToArray(); + Assert.True(areAllItemsRead); + Assert.Empty(feed.Items); + + Assert.Equal(2, items.Length); + + Assert.Equal("id1", items[0].Id); + Assert.Null(items[0].SourceFeed); + + Assert.Equal("id2", items[1].Id); + Assert.Null(items[1].SourceFeed); + } + } + + [Fact] + public void ReadItems_NullReader_ThrowsArgumentNullException() + { + var formatter = new Formatter(); + AssertExtensions.Throws("reader", () => formatter.ReadItemsEntryPoint(null, new SyndicationFeed(), out var areAllItemsReader)); + } + + [Fact] + public void ReadItems_NullFeed_ThrowsArgumentNullException() + { + using (var stringReader = new StringReader("")) + using (XmlReader reader = XmlReader.Create(stringReader)) + { + var formatter = new Formatter(); + AssertExtensions.Throws("feed", () => formatter.ReadItemsEntryPoint(reader, null, out var areAllItemsReader)); + } + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void PreserveAttributeExtensions_Set_GetReturnsExpected(bool preserveAttributeExtensions) + { + var formatter = new Rss20FeedFormatter() { PreserveAttributeExtensions = preserveAttributeExtensions }; + Assert.Equal(preserveAttributeExtensions, formatter.PreserveAttributeExtensions); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void PreserveElementExtensions_Set_GetReturnsExpected(bool preserveElementExtensions) + { + var formatter = new Rss20FeedFormatter { PreserveElementExtensions = preserveElementExtensions }; + Assert.Equal(preserveElementExtensions, formatter.PreserveElementExtensions); + } + + [Fact] + public void CreateFeedInstance_NonGeneric_Success() + { + var formatter = new Formatter(); + SyndicationFeed feed = Assert.IsType(formatter.CreateFeedInstanceEntryPoint()); + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + + var typedFormatter = new Formatter(typeof(SyndicationFeedSubclass)); + feed = Assert.IsType(typedFormatter.CreateFeedInstanceEntryPoint()); + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + } + + [Fact] + public void CreateItemInstance_Generic_Success() + { + var formatter = new GenericFormatter(); + SyndicationFeed feed = Assert.IsType(formatter.CreateFeedInstanceEntryPoint()); + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + + var typedFormatter = new GenericFormatter(); + feed = Assert.IsType(typedFormatter.CreateFeedInstanceEntryPoint()); + Assert.Empty(feed.AttributeExtensions); + Assert.Empty(feed.Authors); + Assert.Null(feed.BaseUri); + Assert.Empty(feed.Categories); + Assert.Empty(feed.Contributors); + Assert.Null(feed.Copyright); + Assert.Null(feed.Description); + Assert.Empty(feed.ElementExtensions); + Assert.Null(feed.Generator); + Assert.Null(feed.Id); + Assert.Null(feed.ImageUrl); + Assert.Empty(feed.Items); + Assert.Null(feed.Language); + Assert.Equal(DateTimeOffset.MinValue, feed.LastUpdatedTime); + Assert.Empty(feed.Links); + Assert.Null(feed.Title); + } + + public class SyndicationFeedSubclass : SyndicationFeed { } + + public class SyndicationFeedTryParseTrueSubclass : SyndicationFeed + { + protected override bool TryParseAttribute(string name, string ns, string value, string version) => true; + + protected override bool TryParseElement(XmlReader reader, string version) + { + reader.Skip(); + return true; + } + + protected override SyndicationCategory CreateCategory() => new SyndicationCategoryTryParseTrueSubclass(); + + protected override SyndicationItem CreateItem() => new SyndicationItemTryParseTrueSubclass(); + + protected override SyndicationLink CreateLink() => new SyndicationLinkTryParseTrueSubclass(); + + protected override SyndicationPerson CreatePerson() => new SyndicationPersonTryParseTrueSubclass(); + } + + public class SyndicationItemTryParseTrueSubclass : SyndicationItem + { + protected override bool TryParseAttribute(string name, string ns, string value, string version) => true; + + protected override bool TryParseContent(XmlReader reader, string contentType, string version, out SyndicationContent content) + { + reader.Skip(); + + content = new TextSyndicationContent("overriden"); + return true; + } + + protected override bool TryParseElement(XmlReader reader, string version) + { + reader.Skip(); + return true; + } + + protected override SyndicationCategory CreateCategory() => new SyndicationCategoryTryParseTrueSubclass(); + + protected override SyndicationPerson CreatePerson() => new SyndicationPersonTryParseTrueSubclass(); + + protected override SyndicationLink CreateLink() => new SyndicationLinkTryParseTrueSubclass(); + } + + public class SyndicationCategoryTryParseTrueSubclass : SyndicationCategory + { + protected override bool TryParseAttribute(string name, string ns, string value, string version) => true; + + protected override bool TryParseElement(XmlReader reader, string version) + { + reader.Skip(); + return true; + } + } + + public class SyndicationPersonTryParseTrueSubclass : SyndicationPerson + { + protected override bool TryParseAttribute(string name, string ns, string value, string version) => true; + + protected override bool TryParseElement(XmlReader reader, string version) + { + reader.Skip(); + return true; + } + } + + public class SyndicationLinkTryParseTrueSubclass : SyndicationLink + { + protected override bool TryParseAttribute(string name, string ns, string value, string version) => true; + + protected override bool TryParseElement(XmlReader reader, string version) + { + reader.Skip(); + return true; + } + } + + public class NullCreatedFeedFormatter : Atom10FeedFormatter + { + protected override SyndicationFeed CreateFeedInstance() => null; + } + + public class Formatter : Rss20FeedFormatter + { + public Formatter() : base() { } + + public Formatter(SyndicationFeed feedToWrite) : base(feedToWrite) { } + + public Formatter(SyndicationFeed feedToWrite, bool serializeExtensionsAsAtom) : base(feedToWrite, serializeExtensionsAsAtom) { } + + public Formatter(Type feedTypeToCreate) : base(feedTypeToCreate) { } + + public Type FeedTypeEntryPoint => FeedType; + + public SyndicationFeed CreateFeedInstanceEntryPoint() => CreateFeedInstance(); + + public void WriteItemEntryPoint(XmlWriter writer, SyndicationItem item, Uri feedBaseUri) => WriteItem(writer, item, feedBaseUri); + + public void WriteItemsEntryPoint(XmlWriter writer, IEnumerable items, Uri feedBaseUri) => WriteItems(writer, items, feedBaseUri); + + public SyndicationItem ReadItemEntryPoint(XmlReader reader, SyndicationFeed feed) => ReadItem(reader, feed); + + public IEnumerable ReadItemsEntryPoint(XmlReader reader, SyndicationFeed feed, out bool areAllItemsRead) + { + return ReadItems(reader, feed, out areAllItemsRead); + } + } + + public class GenericFormatter : Rss20FeedFormatter where T : SyndicationFeed, new() + { + public GenericFormatter() : base() { } + + public GenericFormatter(T feedToWrite) : base(feedToWrite) { } + + public GenericFormatter(T feedToWrite, bool serializeExtensionsAsAtom) : base(feedToWrite, serializeExtensionsAsAtom) { } + + public Type FeedTypeEntryPoint => FeedType; + + public SyndicationFeed CreateFeedInstanceEntryPoint() => CreateFeedInstance(); + } + + [DataContract] + public class ExtensionObject + { + [DataMember] + public int Value { get; set; } + } + } +} diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20ItemFormatterTests.cs b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20ItemFormatterTests.cs index 64d1717..56b7c00 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20ItemFormatterTests.cs +++ b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/Rss20ItemFormatterTests.cs @@ -51,6 +51,20 @@ namespace System.ServiceModel.Syndication.Tests Assert.Equal("Rss20", formatter.Version); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Ctor_SyndicationItem_Bool(bool serializeExtensionsAsAtom) + { + var item = new SyndicationItem(); + var formatter = new Formatter(item, serializeExtensionsAsAtom); + Assert.Equal(typeof(SyndicationItem), formatter.ItemTypeEntryPoint); + Assert.Same(item, formatter.Item); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + [Fact] public void Ctor_GenericSyndicationItem() { @@ -63,6 +77,20 @@ namespace System.ServiceModel.Syndication.Tests Assert.Equal("Rss20", formatter.Version); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Ctor_GenericSyndicationItem_Bool(bool serializeExtensionsAsAtom) + { + var item = new SyndicationItem(); + var formatter = new GenericFormatter(item, serializeExtensionsAsAtom); + Assert.Equal(typeof(SyndicationItem), formatter.ItemTypeEntryPoint); + Assert.Same(item, formatter.Item); + Assert.True(formatter.PreserveAttributeExtensions); + Assert.True(formatter.PreserveElementExtensions); + Assert.Equal("Rss20", formatter.Version); + } + [Fact] public void Ctor_NullItemToWrite_ThrowsArgumentNullException() { @@ -512,7 +540,7 @@ namespace System.ServiceModel.Syndication.Tests [Theory] [MemberData(nameof(WriteTo_TestData))] - public void WriteTo_HasItem_SerializesExpected(SyndicationItem item, bool serializeExtensionsAsAtom, string expected) + public void WriteTo_Invoke_SerializesExpected(SyndicationItem item, bool serializeExtensionsAsAtom, string expected) { var formatter = new Rss20ItemFormatter(item) { SerializeExtensionsAsAtom = serializeExtensionsAsAtom }; CompareHelper.AssertEqualWriteOutput(expected, writer => formatter.WriteTo(writer)); @@ -1843,6 +1871,8 @@ namespace System.ServiceModel.Syndication.Tests public Formatter(SyndicationItem itemToWrite) : base(itemToWrite) { } + public Formatter(SyndicationItem itemToWrite, bool serializeExtensionsAsAtom) : base(itemToWrite, serializeExtensionsAsAtom) { } + public Formatter(Type itemTypeToCreate) : base(itemTypeToCreate) { } public Type ItemTypeEntryPoint => ItemType; @@ -1856,6 +1886,8 @@ namespace System.ServiceModel.Syndication.Tests public GenericFormatter(T itemToWrite) : base(itemToWrite) { } + public GenericFormatter(T itemToWrite, bool serializeExtensionsAsAtom) : base(itemToWrite, serializeExtensionsAsAtom) { } + public Type ItemTypeEntryPoint => ItemType; public SyndicationItem CreateItemInstanceEntryPoint() => CreateItemInstance(); diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.cs b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.cs index 1119260..fc4e519 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.cs +++ b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.cs @@ -22,12 +22,12 @@ namespace System.ServiceModel.Syndication.Tests public static IEnumerable Ctor_Items_TestData() { - yield return new object[] { null }; yield return new object[] { new SyndicationItem[0] }; yield return new object[] { new SyndicationItem[] { new SyndicationItem(), null } }; } [Theory] + [InlineData(null)] [MemberData(nameof(Ctor_Items_TestData))] public void Ctor_Items(IEnumerable items) { @@ -236,6 +236,14 @@ namespace System.ServiceModel.Syndication.Tests } [Fact] + public void Load_InvalidReader_ThrowsXmlException() + { + XmlReader reader = new XElement("invalid").CreateReader(); + Assert.Throws(() => SyndicationFeed.Load(reader)); + Assert.Throws(() => SyndicationFeed.Load(reader)); + } + + [Fact] public void GetAtom10Formatter_Invoke_ReturnsExpected() { var feed = new SyndicationFeed(); @@ -389,6 +397,24 @@ namespace System.ServiceModel.Syndication.Tests AssertExtensions.Throws("writer", () => feed.WriteElementExtensionsEntryPoint(null, "version")); } + [Theory] + [MemberData(nameof(Ctor_Items_TestData))] + public void Items_Set_GetReturnsExpected(IEnumerable value) + { + var feed = new SyndicationFeed + { + Items = value + }; + Assert.Same(value, feed.Items); + } + + [Fact] + public void Items_SetNull_ThrowsArgumentNullException() + { + var feed = new SyndicationFeed(); + AssertExtensions.Throws("value", () => feed.Items = null); + } + private static void VerifySyndicationFeed(SyndicationFeed feed, string title, string description, Uri feedAlternateLink, string id, DateTimeOffset lastUpdatedTime, IEnumerable items) { Assert.Empty(feed.AttributeExtensions); diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.netcoreapp.cs b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.netcoreapp.cs index 52ebf7a..fbb391c 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.netcoreapp.cs +++ b/src/libraries/System.ServiceModel.Syndication/tests/System/ServiceModel/Syndication/SyndicationFeedTests.netcoreapp.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Xml.Linq; using Xunit; namespace System.ServiceModel.Syndication.Tests @@ -125,5 +127,200 @@ namespace System.ServiceModel.Syndication.Tests Assert.Null(clone.TextInput); Assert.Null(clone.TimeToLive); } + + [Fact] + public void SkipHours_GetWithElementExtension_ReturnsExpected() + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(new SyndicationElementExtension("other", "", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("skipHours", "other", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension( + new XElement("skipHours", + new XElement("hour", 0), + new XElement("hour", 10), + new XElement("other", 10), + new XElement("hour", 23) + ).CreateReader()) + ); + + Assert.Equal(new int[] { 0, 10, 23 }, feed.SkipHours); + Assert.Same(feed.SkipHours, feed.SkipHours); + } + + [Theory] + [InlineData(-1)] + [InlineData(24)] + [InlineData("invalid")] + [InlineData("")] + public void SkipHours_GetWithInvalidElementExtension_ThrowsFormatException(string value) + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(new SyndicationElementExtension("other", "", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("skipHours", "other", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension( + new XElement("skipHours", + new XElement("hour", 0), + new XElement("hour", 10), + new XElement("other", 10), + new XElement("hour", value) + ).CreateReader()) + ); + + Assert.Throws(() => feed.SkipHours); + } + + [Fact] + public void SkipDays_GetWithElementExtension_ReturnsExpected() + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(new SyndicationElementExtension("other", "", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("skipDays", "other", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension( + new XElement("skipDays", + new XElement("day", "monday"), + new XElement("day", "tuesday"), + new XElement("other", 10), + new XElement("day", "wednesday"), + new XElement("day", "thursday"), + new XElement("day", "friday"), + new XElement("day", "SATURDAY"), + new XElement("day", ""), + new XElement("day", "invalid"), + new XElement("day", "sunday") + ).CreateReader()) + ); + + Assert.Equal(new string[] { "monday", "tuesday", "wednesday", "thursday", "friday", "SATURDAY", "sunday" }, feed.SkipDays); + Assert.Same(feed.SkipDays, feed.SkipDays); + } + + [Fact] + public void TextInput_GetWithElementExtension_ReturnsExpected() + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(new SyndicationElementExtension("other", "", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("textInput", "other", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension( + new XElement("textInput", + new XElement("name", "Name"), + new XElement("description", "Description"), + new XElement("other", 10), + new XElement("title", "Title"), + new XElement("link", "http://google.com") + ).CreateReader()) + ); + + Assert.Equal("Name", feed.TextInput.Name); + Assert.Equal("Description", feed.TextInput.Description); + Assert.Equal("Title", feed.TextInput.Title); + Assert.Equal(new Uri("http://google.com"), feed.TextInput.Link.Uri); + } + + public static IEnumerable TextInput_GetInvalid_TestData() + { + yield return new object[] + { + new SyndicationElementExtension( + new XElement("textInput", + new XElement("description", "Description"), + new XElement("title", "Title"), + new XElement("link", "http://google.com") + ).CreateReader() + ) + }; + yield return new object[] + { + new SyndicationElementExtension( + new XElement("textInput", + new XElement("name", "Name"), + new XElement("title", "Title"), + new XElement("link", "http://google.com") + ).CreateReader() + ) + }; + yield return new object[] + { + new SyndicationElementExtension( + new XElement("textInput", + new XElement("name", "Name"), + new XElement("description", "Description"), + new XElement("link", "http://google.com") + ).CreateReader() + ) + }; + yield return new object[] + { + new SyndicationElementExtension( + new XElement("textInput", + new XElement("name", "Name"), + new XElement("description", "Description"), + new XElement("title", "Title") + ).CreateReader() + ) + }; + } + + [Theory] + [MemberData(nameof(TextInput_GetInvalid_TestData))] + public void TextInput_GetInvalid_ReturnsNull(SyndicationElementExtension extension) + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(extension); + Assert.Null(feed.TextInput); + } + + public static IEnumerable TimeToLive_GetWithElementExtension_TestData() + { + yield return new object[] { 10, TimeSpan.FromMinutes(10) }; + yield return new object[] { -1, null }; + yield return new object[] { "", null }; + yield return new object[] { "invalid", null }; + } + + [Theory] + [MemberData(nameof(TimeToLive_GetWithElementExtension_TestData))] + public void TimeToLive_GetWithElementExtension_ReturnsExpected(object value, TimeSpan? expectedValue) + { + var feed = new SyndicationFeed(); + feed.ElementExtensions.Add(new SyndicationElementExtension("other", "", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("ttl", "other", 10)); + feed.ElementExtensions.Add(new SyndicationElementExtension("ttl", "", value)); + + Assert.Equal(expectedValue, feed.TimeToLive); + } + + public static IEnumerable TimeToLive_Set_TestData() + { + yield return new object[] { null }; + yield return new object[] { new TimeSpan(hours: 0, minutes: 0, seconds: 0) }; + yield return new object[] { new TimeSpan(hours: 0, minutes: 1, seconds: 0) }; + yield return new object[] { new TimeSpan(hours: 0, minutes: 1000, seconds: 0) }; + } + + [Theory] + [MemberData(nameof(TimeToLive_Set_TestData))] + public static void TimeToLive_Set_GetReturnsExpected(TimeSpan? value) + { + var feed = new SyndicationFeed + { + TimeToLive = value + }; + Assert.Equal(value, feed.TimeToLive); + } + + public static IEnumerable TimeToLive_SetInvalid_TestData() + { + yield return new object[] { new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 1, milliseconds: 0) }; + yield return new object[] { new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 0, milliseconds: 1) }; + yield return new object[] { new TimeSpan(hours: 0, minutes: -1, seconds: 0) }; + } + + [Theory] + [MemberData(nameof(TimeToLive_SetInvalid_TestData))] + public void TimeToLive_SetInvalid_ThrowsArgumentOutOfRangeException(TimeSpan value) + { + var feed = new SyndicationFeed(); + Assert.Throws("value", () => feed.TimeToLive = value); + } } } diff --git a/src/libraries/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs b/src/libraries/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs index 8da9b2a..6cce9b3 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs +++ b/src/libraries/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs @@ -200,62 +200,5 @@ namespace System.ServiceModel.Syndication.Tests }); } - public static TheoryData InvalidTimeToLiveValues - { - get - { - TheoryData data = new TheoryData(); - - data.Add(new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 1, milliseconds: 0)); - data.Add(new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 0, milliseconds: 1)); - data.Add(new TimeSpan(hours: 0, minutes: -1, seconds: 0)); - - return data; - } - } - - public static TheoryData ValidTimeToLiveValues - { - get - { - TheoryData data = new TheoryData(); - - data.Add(new TimeSpan(hours: 0, minutes: 0, seconds: 0)); - data.Add(new TimeSpan(hours: 0, minutes: 1, seconds: 0)); - data.Add(new TimeSpan(hours: 0, minutes: 1000, seconds: 0)); - - return data; - } - } - - [Theory, MemberData(nameof(InvalidTimeToLiveValues))] - public static void SyndicationFeed_TimeToLive_Validation_Throws(TimeSpan invalidTimeToLive) - { - Assert.Throws(() => - { - var feed = new SyndicationFeed("Contoso News", "
Most recent news from Contoso
", - new Uri("http://www.Contoso.com/news")); - feed.TimeToLive = invalidTimeToLive; - }); - } - - [Theory, MemberData(nameof(ValidTimeToLiveValues))] - public static void SyndicationFeed_TimeToLive_Success(TimeSpan validTimeToLive) - { - var feed = new SyndicationFeed("Contoso News", "
Most recent news from Contoso
", - new Uri("http://www.Contoso.com/news")); - feed.TimeToLive = validTimeToLive; - Assert.Equal(validTimeToLive, feed.TimeToLive.Value); - } - - [Fact] - public static void SyndicationFeed_TimeToLive_Null_Success() - { - var feed = new SyndicationFeed("Contoso News", "
Most recent news from Contoso
", - new Uri("http://www.Contoso.com/news")); - feed.TimeToLive = null; - Assert.False(feed.TimeToLive.HasValue); - } - } } -- 2.7.4