From 3edf806f1f1bc2cde58f12da7815ac63268b8965 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 8 Sep 2011 20:19:04 +0100 Subject: [PATCH] Added ExpressionToCode library for unit test expression-based asserts. Added Xml(De)Serializers based on .Net framework XmlSerializer. Updated Subscriber and SubscriberList entity definitions to use Xml attributes rather than the RestSharp attributes. Added dedicated Deserialization unit tests for SubscriberList. --- Spreedly.Net/Client/SpreedlyClient.cs | 5 + Spreedly.Net/Entities/Subscriber.cs | 138 +++++++++++------- Spreedly.Net/Entities/SubscriberList.cs | 5 +- Spreedly.Net/Spreedly.Net.csproj | 3 + Spreedly.Net/Xml/FrameworkDeserializer.cs | 31 ++++ Spreedly.Net/Xml/FrameworkSerializer.cs | 46 ++++++ Spreedly.Net/Xml/SerializableNullable.cs | 88 +++++++++++ .../Deserialize/SubscriberListTests.cs | 101 +++++++++++++ .../SubscriberIntegrationTests.cs | 2 +- Spreedly.NetTests/Spreedly.NetTests.csproj | 4 + _ExternalReferences/ExpressionToCodeLib.dll | Bin 0 -> 34816 bytes 11 files changed, 371 insertions(+), 52 deletions(-) create mode 100644 Spreedly.Net/Xml/FrameworkDeserializer.cs create mode 100644 Spreedly.Net/Xml/FrameworkSerializer.cs create mode 100644 Spreedly.Net/Xml/SerializableNullable.cs create mode 100644 Spreedly.NetTests/Deserialize/SubscriberListTests.cs create mode 100644 _ExternalReferences/ExpressionToCodeLib.dll diff --git a/Spreedly.Net/Client/SpreedlyClient.cs b/Spreedly.Net/Client/SpreedlyClient.cs index 21437bd..4e1d49b 100644 --- a/Spreedly.Net/Client/SpreedlyClient.cs +++ b/Spreedly.Net/Client/SpreedlyClient.cs @@ -4,6 +4,7 @@ using System.Net; using RestSharp; using System.Linq; + using Xml; public class SpreedlyClient: ISpreedlyClient { @@ -93,6 +94,10 @@ private RestClient GetClient() { var client = new RestClient(BaseSpreedlyUrl); client.Authenticator = new HttpBasicAuthenticator(_userName, _password); + client.RemoveHandler("application/xml"); + client.RemoveHandler("text/xml"); + client.AddHandler("application/xml", new FrameworkDeserializer()); + client.AddHandler("text/xml", new FrameworkDeserializer()); return client; } diff --git a/Spreedly.Net/Entities/Subscriber.cs b/Spreedly.Net/Entities/Subscriber.cs index 77c1c96..af150be 100644 --- a/Spreedly.Net/Entities/Subscriber.cs +++ b/Spreedly.Net/Entities/Subscriber.cs @@ -1,75 +1,113 @@ namespace Spreedly.Net.Entities { using System; - using RestSharp.Serializers; + using System.Xml.Serialization; + using Xml; - [SerializeAs(NameStyle = NameStyle.LowerCase)] + [XmlRoot(ElementName = "subscriber")] public class Subscriber { - public bool? Active { get; set; } - [SerializeAs(Name = "active-until")] - public DateTime? ActiveUntil { get; set; } - [SerializeAs(Name = "billing-first-name")] + [XmlElement(ElementName = "active", IsNullable = true)] + public SerializableNullable Active { get; set; } + + [XmlElement(ElementName = "active-until", IsNullable = true)] + public SerializableNullable ActiveUntil { get; set; } + + [XmlElement(ElementName = "billing-first-name")] public string BillingFirstName { get; set; } - [SerializeAs(Name = "billing-last-name")] + + [XmlElement(ElementName = "billing-last-name")] public string BillingLastName { get; set; } - [SerializeAs(Name = "card-expires-before-next-auto-renew")] - public bool? CardExpiresBeforeNextAutoRenew { get; set; } - [SerializeAs(Name = "created-at")] - public DateTime? CreatedAt { get; set; } - [SerializeAs(Name = "customer-id")] + + [XmlElement(ElementName = "card-expires-before-next-auto-renew", IsNullable = true)] + public SerializableNullable CardExpiresBeforeNextAutoRenew { get; set; } + + [XmlElement(ElementName = "created-at", IsNullable = true)] + public SerializableNullable CreatedAt { get; set; } + + [XmlElement(ElementName = "customer-id")] public string CustomerId { get; set; } - [SerializeAs(Name = "eligible-for-free-trial")] - public bool? EligibleForFreeTrial { get; set; } + + [XmlElement(ElementName = "eligible-for-free-trial", IsNullable = true)] + public SerializableNullable EligibleForFreeTrial { get; set; } + + [XmlElement(ElementName = "email")] public string Email { get; set; } - [SerializeAs(Name = "feature-level")] + + [XmlElement(ElementName = "feature-level")] public string FeatureLevel { get; set; } - [SerializeAs(Name = "lifetime-subscription")] - public bool? LifetimeSubscription { get; set; } - [SerializeAs(Name = "on-trial")] - public bool? OnTrial { get; set; } - [SerializeAs(Name = "on-gift")] - public bool? OnGift { get; set; } - [SerializeAs(Name = "on-metered")] - public bool? OnMetered { get; set; } - public bool? Recurring { get; set; } - [SerializeAs(Name = "screen-name")] + + [XmlElement(ElementName = "lifetime-subscription", IsNullable = true)] + public SerializableNullable LifetimeSubscription { get; set; } + + [XmlElement(ElementName = "on-trial", IsNullable = true)] + public SerializableNullable OnTrial { get; set; } + + [XmlElement(ElementName = "on-gift", IsNullable = true)] + public SerializableNullable OnGift { get; set; } + + [XmlElement(ElementName = "on-metered")] + public SerializableNullable OnMetered { get; set; } + + [XmlElement(ElementName = "recurring", IsNullable = true)] + public SerializableNullable Recurring { get; set; } + + [XmlElement(ElementName = "screen-name")] public string ScreenName { get; set; } - [SerializeAs(Name = "store-credit")] - public decimal? StoreCredit { get; set; } - [SerializeAs(Name = "store-credit-currency-code")] + + [XmlElement(ElementName = "store-credit")] + public SerializableNullable StoreCredit { get; set; } + + [XmlElement(ElementName = "store-credit-currency-code")] public string StoreCreditCurrencyCode { get; set; } - [SerializeAs(Name = "subscription-plan-name")] + + [XmlElement(ElementName = "subscription-plan-name")] public string SubscriptionPlanName { get; set; } + + [XmlElement(ElementName = "token")] public string Token { get; set; } - [SerializeAs(Name = "updated-at")] - public DateTime? UpdatedAt { get; set; } - [SerializeAs(Name = "grace-until")] - public DateTime? GraceUntil { get; set; } - [SerializeAs(Name = "in-grace-period")] - public bool? InGracePeriod { get; set; } - [SerializeAs(Name = "ready-to-renew")] - public bool? ReadyToRenew { get; set; } - [SerializeAs(Name = "ready-to-renew-since")] - public DateTime? ReadyToRenewSince { get; set; } - [SerializeAs(Name = "payment-account-on-file")] - public bool? PaymentAccountOnFile { get; set; } - [SerializeAs(Name = "payment-account-display")] - public bool? PaymentAccountDisplay { get; set; } - [SerializeAs(Name = "billing-address1")] + + [XmlElement(ElementName = "updated-at", IsNullable = true)] + public SerializableNullable UpdatedAt { get; set; } + + [XmlElement(ElementName = "grace-until", IsNullable = true)] + public SerializableNullable GraceUntil { get; set; } + + [XmlElement(ElementName = "in-grace-period", IsNullable = true)] + public SerializableNullable InGracePeriod { get; set; } + + [XmlElement(ElementName = "ready-to-renew", IsNullable = true)] + public SerializableNullable ReadyToRenew { get; set; } + + [XmlElement(ElementName = "ready-to-renew-since", IsNullable = true)] + public SerializableNullable ReadyToRenewSince { get; set; } + + [XmlElement(ElementName = "payment-account-on-file", IsNullable = true)] + public SerializableNullable PaymentAccountOnFile { get; set; } + + [XmlElement(ElementName = "payment-account-display", IsNullable = true)] + public string PaymentAccountDisplay { get; set; } + + [XmlElement(ElementName = "billing-address1")] public string BillingAddress1 { get; set; } - [SerializeAs(Name = "billing-city")] + + [XmlElement(ElementName = "billing-city")] public string BillingCity { get; set; } - [SerializeAs(Name = "billing-state")] + + [XmlElement(ElementName = "billing-state")] public string BillingState { get; set; } - [SerializeAs(Name = "billing-zip")] + + [XmlElement(ElementName = "billing-zip")] public string BillingZip { get; set; } - [SerializeAs(Name = "billing-country")] + + [XmlElement(ElementName = "billing-country")] public string BillingCountry { get; set; } - [SerializeAs(Name = "billing-phone-number")] + + [XmlElement(ElementName = "billing-phone-number")] public string BillingPhoneNumber { get; set; } - [SerializeAs(Name = "payment-method")] + + [XmlElement(ElementName = "payment-method")] public CreditCard PaymentMethod { get; set; } } } \ No newline at end of file diff --git a/Spreedly.Net/Entities/SubscriberList.cs b/Spreedly.Net/Entities/SubscriberList.cs index 5e406db..c644dfe 100644 --- a/Spreedly.Net/Entities/SubscriberList.cs +++ b/Spreedly.Net/Entities/SubscriberList.cs @@ -1,9 +1,12 @@ namespace Spreedly.Net.Entities { using System.Collections.Generic; - + using System.Xml.Serialization; + + [XmlRoot(ElementName = "subscribers")] public class SubscriberList { + [XmlElement(ElementName = "subscriber")] public List Subscribers { get; set; } public SubscriberList() diff --git a/Spreedly.Net/Spreedly.Net.csproj b/Spreedly.Net/Spreedly.Net.csproj index a0d70cb..5b74127 100644 --- a/Spreedly.Net/Spreedly.Net.csproj +++ b/Spreedly.Net/Spreedly.Net.csproj @@ -68,6 +68,9 @@ + + + diff --git a/Spreedly.Net/Xml/FrameworkDeserializer.cs b/Spreedly.Net/Xml/FrameworkDeserializer.cs new file mode 100644 index 0000000..b082a34 --- /dev/null +++ b/Spreedly.Net/Xml/FrameworkDeserializer.cs @@ -0,0 +1,31 @@ +namespace Spreedly.Net.Xml +{ + using System.IO; + using System.Xml; + using System.Xml.Serialization; + using RestSharp; + using RestSharp.Deserializers; + + public class FrameworkDeserializer: IDeserializer + { + public T Deserialize(RestResponse response) where T : new() + { + if (response == null || response.Content == null) + return default(T); + + XmlDocument doc; + return Deserialize(XmlReader.Create(new StringReader(response.Content))); + } + + private T Deserialize(XmlReader contentReader) + { + var serializer = new XmlSerializer(typeof (T)); + return (T)serializer.Deserialize(contentReader); + } + + public string RootElement { get; set; } + public string Namespace { get; set; } + public string DateFormat { get; set; } + } + +} \ No newline at end of file diff --git a/Spreedly.Net/Xml/FrameworkSerializer.cs b/Spreedly.Net/Xml/FrameworkSerializer.cs new file mode 100644 index 0000000..0620334 --- /dev/null +++ b/Spreedly.Net/Xml/FrameworkSerializer.cs @@ -0,0 +1,46 @@ +namespace Spreedly.Net.Xml +{ + using System.IO; + using System.Text; + using System.Xml.Serialization; + using RestSharp.Serializers; + + public class FrameworkSerializer: ISerializer + { + public string Serialize(object obj) + { + var ns = new XmlSerializerNamespaces(); + ns.Add(string.Empty, this.Namespace); + var serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); + var writer = new EncodingStringWriter(this.Encoding); + serializer.Serialize(writer, obj, ns); + + return writer.ToString(); + } + + public Encoding Encoding { get; set; } + public string RootElement { get; set; } + public string Namespace { get; set; } + public string DateFormat { get; set; } + public string ContentType { get; set; } + + + private class EncodingStringWriter : StringWriter + { + private readonly Encoding encoding; + + public EncodingStringWriter(Encoding encoding) + { + this.encoding = encoding; + } + + public override Encoding Encoding + { + get + { + return this.encoding; + } + } + } + } +} \ No newline at end of file diff --git a/Spreedly.Net/Xml/SerializableNullable.cs b/Spreedly.Net/Xml/SerializableNullable.cs new file mode 100644 index 0000000..d33aaff --- /dev/null +++ b/Spreedly.Net/Xml/SerializableNullable.cs @@ -0,0 +1,88 @@ +namespace Spreedly.Net.Xml +{ + using System; + using System.ComponentModel; + using System.Xml; + using System.Xml.Schema; + using System.Xml.Serialization; + + public struct SerializableNullable : IXmlSerializable, IEquatable> where T : struct + { + private T value; + private bool hasValue; + + private SerializableNullable(T value) + { + hasValue = true; + this.value = value; + } + + public bool HasValue + { + get { return hasValue; } + } + + public T Value + { + get { return value; } + } + + XmlSchema IXmlSerializable.GetSchema() + { + return null; + } + + void IXmlSerializable.ReadXml(XmlReader reader) + { + if (reader.GetAttribute("nil") == "true") + { + ReadNullValue(); + return; + } + ReadNonNullValue(reader); + } + + void IXmlSerializable.WriteXml(XmlWriter writer) + { + if(HasValue) + writer.WriteValue(value); + else + { + writer.WriteAttributeString("nil", string.Empty, "true"); + writer.WriteValue(string.Empty); + } + } + + private void ReadNullValue() + { + hasValue = false; + } + + private void ReadNonNullValue(XmlReader reader) + { + reader.ReadStartElement(); + var s = reader.ReadString(); + value = GetValue(s); + reader.ReadEndElement(); + hasValue = true; + } + + private T GetValue(string readValue) + { + var descriptor = TypeDescriptor.GetConverter(typeof (T)); + if (descriptor.CanConvertFrom(typeof(string))) + return (T)descriptor.ConvertFromInvariantString(readValue); + return default(T); + } + + public static implicit operator SerializableNullable(T value) + { + return new SerializableNullable(value); + } + + public bool Equals(SerializableNullable other) + { + return HasValue == other.HasValue && Value.Equals(other.Value); + } + } +} \ No newline at end of file diff --git a/Spreedly.NetTests/Deserialize/SubscriberListTests.cs b/Spreedly.NetTests/Deserialize/SubscriberListTests.cs new file mode 100644 index 0000000..cf40e82 --- /dev/null +++ b/Spreedly.NetTests/Deserialize/SubscriberListTests.cs @@ -0,0 +1,101 @@ +namespace Spreedly.NetTests.Deserialize +{ + using System.IO; + using System.Linq; + using System.Xml; + using System.Xml.Serialization; + using ExpressionToCodeLib; + using NUnit.Framework; + using Net.Entities; + + public class SubscriberListTests + { + private const string xmlList = @" + + + 2011-09-07T16:34:20Z + 001 + ScreenName1 + + + 2011-09-02T16:10:53Z + 2095 + + + + 2011-09-02T16:09:55Z + 88225 + + + + 2011-09-06T16:59:34Z + aef789956af61024d82ec270039601b91e06262a + + + +"; + private const string emptyXml = @" + + +"; + + private XmlSerializer _serializer; + + [SetUp] + public void Init() + { + _serializer = new XmlSerializer(typeof(SubscriberList)); + } + + [Test] + public void Deserializing_ValidSubscriberList_ThrowsNoException() + { + var subscriberList = (SubscriberList) _serializer.Deserialize(XmlReader.Create(new StringReader(xmlList))); + + Assert.True(true); + } + + [Test] + public void Deserializing_ValidSubscriberList_ReturnsNotNullList() + { + var subscriberList = (SubscriberList)_serializer.Deserialize(XmlReader.Create(new StringReader(xmlList))); + + Assert.NotNull(subscriberList); + } + + [Test] + public void Deserializing_NonEmptySubscriberList_ReturnsNonEmptyList() + { + var subscriberList = (SubscriberList)_serializer.Deserialize(XmlReader.Create(new StringReader(xmlList))); + + Assert.True(subscriberList.Subscribers.Count > 0); + } + + [Test] + public void Deserializing_EmptyList_ReturnsNotNullList() + { + var subscriberList = (SubscriberList)_serializer.Deserialize(XmlReader.Create(new StringReader(emptyXml))); + + Assert.NotNull(subscriberList); + } + + [Test] + public void Deserializing_EmptyList_ReturnsEmptyList() + { + var subscriberList = (SubscriberList)_serializer.Deserialize(XmlReader.Create(new StringReader(emptyXml))); + + Assert.AreEqual(0, subscriberList.Subscribers.Count); + } + + [Test] + public void Deserializing_NonEmptyList_ReturnsExpectedSubscribers() + { + var subscriberList = (SubscriberList)_serializer.Deserialize(XmlReader.Create(new StringReader(xmlList))); + + PAssert.That( + () => + subscriberList.Subscribers.OrderBy(s => s.CustomerId).Select(s => s.CustomerId).Aggregate(string.Empty, (accum, item) => accum + "," + item) + == ",001,2095,88225,aef789956af61024d82ec270039601b91e06262a"); + } + } +} \ No newline at end of file diff --git a/Spreedly.NetTests/IntegrationTests/SubscriberIntegrationTests.cs b/Spreedly.NetTests/IntegrationTests/SubscriberIntegrationTests.cs index f97e81b..7f269f8 100644 --- a/Spreedly.NetTests/IntegrationTests/SubscriberIntegrationTests.cs +++ b/Spreedly.NetTests/IntegrationTests/SubscriberIntegrationTests.cs @@ -27,6 +27,7 @@ public void ListSubscribersForSite_ReturnsStatusOK() var subs = _subscribers.GetSubscribers(); Assert.AreEqual(SpreedlyStatus.Ok, subs.Status); + Assert.True(subs.Entity.Subscribers.Count > 0); } [Test] @@ -35,7 +36,6 @@ public void RetrieveSubscriberUsingCustomerId_ReturnsSubscriber() var custId = "aef789956af61024d82ec270039601b91e06262a"; var sub = _subscribers.GetSubscriberByCustomerId(custId); - Assert.AreEqual(SpreedlyStatus.Ok, sub.Status); Assert.AreEqual(custId, sub.Entity.CustomerId); } diff --git a/Spreedly.NetTests/Spreedly.NetTests.csproj b/Spreedly.NetTests/Spreedly.NetTests.csproj index 981efba..7e48d92 100644 --- a/Spreedly.NetTests/Spreedly.NetTests.csproj +++ b/Spreedly.NetTests/Spreedly.NetTests.csproj @@ -31,6 +31,9 @@ 4 + + ..\_ExternalReferences\ExpressionToCodeLib.dll + ..\Spreedly.Net\packages\Newtonsoft.Json.4.0.2\lib\net40\Newtonsoft.Json.dll @@ -58,6 +61,7 @@ + diff --git a/_ExternalReferences/ExpressionToCodeLib.dll b/_ExternalReferences/ExpressionToCodeLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..0b1939b5593d6c50c039e0f209d0cc2b1eccb333 GIT binary patch literal 34816 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 literal 0 HcmV?d00001