From 4eb15b950efdcd40da58b114b6c4b11ae95fb42d Mon Sep 17 00:00:00 2001 From: Olivier Bellone Date: Fri, 21 Jun 2019 11:13:23 -0700 Subject: [PATCH] Better string enums --- .../Customers/CustomerCreateOptions.cs | 2 +- .../UpcomingInvoiceListLineItemsOptions.cs | 2 +- .../Invoices/UpcomingInvoiceOptions.cs | 2 +- .../Services/Plans/PlanTierOptions.cs | 2 +- src/Stripe.net/Services/Plans/PlanTierUpTo.cs | 15 +++--- .../SubscriptionBillingCycleAnchor.cs | 20 ++++---- .../SubscriptionSharedOptions.cs | 2 +- .../Subscriptions/SubscriptionTrialEnd.cs | 15 +++--- .../SubscriptionUpdateOptions.cs | 2 +- src/Stripe.net/Services/_base/StringEnum.cs | 46 +++++++++++++++++++ .../FormEncoding/FormEncoderTest.cs | 18 ++++++++ .../Infrastructure/TestData/TestOptions.cs | 13 ++++++ 12 files changed, 107 insertions(+), 32 deletions(-) create mode 100644 src/Stripe.net/Services/_base/StringEnum.cs diff --git a/src/Stripe.net/Services/Customers/CustomerCreateOptions.cs b/src/Stripe.net/Services/Customers/CustomerCreateOptions.cs index 565161395a..a152fe05d6 100644 --- a/src/Stripe.net/Services/Customers/CustomerCreateOptions.cs +++ b/src/Stripe.net/Services/Customers/CustomerCreateOptions.cs @@ -114,7 +114,7 @@ public class CustomerCreateOptions : BaseOptions public decimal? TaxPercent { get; set; } [JsonProperty("trial_end")] - public AnyOf TrialEnd { get; set; } + public AnyOf TrialEnd { get; set; } [JsonProperty("validate")] public bool? Validate { get; set; } diff --git a/src/Stripe.net/Services/Invoices/UpcomingInvoiceListLineItemsOptions.cs b/src/Stripe.net/Services/Invoices/UpcomingInvoiceListLineItemsOptions.cs index dfc2771778..41d96204ad 100644 --- a/src/Stripe.net/Services/Invoices/UpcomingInvoiceListLineItemsOptions.cs +++ b/src/Stripe.net/Services/Invoices/UpcomingInvoiceListLineItemsOptions.cs @@ -38,7 +38,7 @@ public class UpcomingInvoiceListLineItemsOptions : ListOptions /// . /// [JsonProperty("subscription_billing_cycle_anchor")] - public AnyOf SubscriptionBillingCycleAnchor { get; set; } + public AnyOf SubscriptionBillingCycleAnchor { get; set; } /// /// Boolean indicating whether this subscription should cancel at the end of the current diff --git a/src/Stripe.net/Services/Invoices/UpcomingInvoiceOptions.cs b/src/Stripe.net/Services/Invoices/UpcomingInvoiceOptions.cs index 989e96797b..ed64cf5aa4 100644 --- a/src/Stripe.net/Services/Invoices/UpcomingInvoiceOptions.cs +++ b/src/Stripe.net/Services/Invoices/UpcomingInvoiceOptions.cs @@ -38,7 +38,7 @@ public class UpcomingInvoiceOptions : BaseOptions /// . /// [JsonProperty("subscription_billing_cycle_anchor")] - public AnyOf SubscriptionBillingCycleAnchor { get; set; } + public AnyOf SubscriptionBillingCycleAnchor { get; set; } /// /// Boolean indicating whether this subscription should cancel at the end of the current diff --git a/src/Stripe.net/Services/Plans/PlanTierOptions.cs b/src/Stripe.net/Services/Plans/PlanTierOptions.cs index 9cd96f2a6c..66eb1d2d5d 100644 --- a/src/Stripe.net/Services/Plans/PlanTierOptions.cs +++ b/src/Stripe.net/Services/Plans/PlanTierOptions.cs @@ -23,6 +23,6 @@ public class PlanTierOptions : INestedOptions /// tier. /// [JsonProperty("up_to")] - public AnyOf UpTo { get; set; } + public AnyOf UpTo { get; set; } } } diff --git a/src/Stripe.net/Services/Plans/PlanTierUpTo.cs b/src/Stripe.net/Services/Plans/PlanTierUpTo.cs index 49bf7009cc..688e931bce 100644 --- a/src/Stripe.net/Services/Plans/PlanTierUpTo.cs +++ b/src/Stripe.net/Services/Plans/PlanTierUpTo.cs @@ -1,14 +1,13 @@ namespace Stripe { - using System.Runtime.Serialization; - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - - [JsonConverter(typeof(StringEnumConverter))] - public enum PlanTierUpTo + public class PlanTierUpTo : StringEnum { /// Use this value to define a fallback tier. - [EnumMember(Value = "inf")] - Inf, + public static readonly PlanTierUpTo Inf = new PlanTierUpTo("inf"); + + private PlanTierUpTo(string value) + : base(value) + { + } } } diff --git a/src/Stripe.net/Services/Subscriptions/SubscriptionBillingCycleAnchor.cs b/src/Stripe.net/Services/Subscriptions/SubscriptionBillingCycleAnchor.cs index 2c6c8b0ed1..022dfed7ff 100644 --- a/src/Stripe.net/Services/Subscriptions/SubscriptionBillingCycleAnchor.cs +++ b/src/Stripe.net/Services/Subscriptions/SubscriptionBillingCycleAnchor.cs @@ -1,18 +1,18 @@ namespace Stripe { - using System.Runtime.Serialization; - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - - [JsonConverter(typeof(StringEnumConverter))] - public enum SubscriptionBillingCycleAnchor + public class SubscriptionBillingCycleAnchor : StringEnum { /// Resets the subscription's billing cycle anchor to the current time. - [EnumMember(Value = "now")] - Now, + public static readonly SubscriptionBillingCycleAnchor Now + = new SubscriptionBillingCycleAnchor("now"); /// Leaves the subscription's billing cycle anchor unchanged. - [EnumMember(Value = "unchanged")] - Unchanged, + public static readonly SubscriptionBillingCycleAnchor Unchanged + = new SubscriptionBillingCycleAnchor("unchanged"); + + private SubscriptionBillingCycleAnchor(string value) + : base(value) + { + } } } diff --git a/src/Stripe.net/Services/Subscriptions/SubscriptionSharedOptions.cs b/src/Stripe.net/Services/Subscriptions/SubscriptionSharedOptions.cs index 14a3b0e321..3508c411b9 100644 --- a/src/Stripe.net/Services/Subscriptions/SubscriptionSharedOptions.cs +++ b/src/Stripe.net/Services/Subscriptions/SubscriptionSharedOptions.cs @@ -106,7 +106,7 @@ public abstract class SubscriptionSharedOptions : BaseOptions /// immediately. /// [JsonProperty("trial_end")] - public AnyOf TrialEnd { get; set; } + public AnyOf TrialEnd { get; set; } /// /// Boolean. Decide whether to use the default trial on the plan when creating a subscription. diff --git a/src/Stripe.net/Services/Subscriptions/SubscriptionTrialEnd.cs b/src/Stripe.net/Services/Subscriptions/SubscriptionTrialEnd.cs index 95c6cb9f04..13446fcbe8 100644 --- a/src/Stripe.net/Services/Subscriptions/SubscriptionTrialEnd.cs +++ b/src/Stripe.net/Services/Subscriptions/SubscriptionTrialEnd.cs @@ -1,14 +1,13 @@ namespace Stripe { - using System.Runtime.Serialization; - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - - [JsonConverter(typeof(StringEnumConverter))] - public enum SubscriptionTrialEnd + public class SubscriptionTrialEnd : StringEnum { /// Special value used to end a customer's trial immediately. - [EnumMember(Value = "now")] - Now, + public static readonly SubscriptionTrialEnd Now = new SubscriptionTrialEnd("now"); + + private SubscriptionTrialEnd(string value) + : base(value) + { + } } } diff --git a/src/Stripe.net/Services/Subscriptions/SubscriptionUpdateOptions.cs b/src/Stripe.net/Services/Subscriptions/SubscriptionUpdateOptions.cs index 5df0a47cfa..b8a358aa4e 100644 --- a/src/Stripe.net/Services/Subscriptions/SubscriptionUpdateOptions.cs +++ b/src/Stripe.net/Services/Subscriptions/SubscriptionUpdateOptions.cs @@ -13,7 +13,7 @@ public class SubscriptionUpdateOptions : SubscriptionSharedOptions /// documentation. /// [JsonProperty("billing_cycle_anchor")] - public SubscriptionBillingCycleAnchor? BillingCycleAnchor { get; set; } + public SubscriptionBillingCycleAnchor BillingCycleAnchor { get; set; } /// /// List of subscription items, each with an attached plan. diff --git a/src/Stripe.net/Services/_base/StringEnum.cs b/src/Stripe.net/Services/_base/StringEnum.cs new file mode 100644 index 0000000000..e9379345cc --- /dev/null +++ b/src/Stripe.net/Services/_base/StringEnum.cs @@ -0,0 +1,46 @@ +namespace Stripe +{ + /// + /// Abstract base class for string enum parameters. + /// + /// + /// This class is used to define request parameters that can only take certain string values. + /// We use it instead of defining a regular enum with + /// annotations for + /// serialization because enum is really an integer under the hood. This can be + /// problematic in some cases, like when a parameter can be an integer OR a string enum (e.g. + /// ). + /// + /// + /// This sample shows how to define a new string enum type. + /// + /// public class FooBar : StringEnum + /// { + /// public static readonly FooBar Foo = new FooBar("foo"); + /// public static readonly FooBar Bar = new FooBar("bar"); + /// + /// private FooBar(string value) : base(value) {} + /// } + /// + /// + public abstract class StringEnum + { + /// Initializes a new instance of the class. + /// The serialized value for the instance. + protected StringEnum(string value) + { + this.Value = value; + } + + /// Gets or sets the serialized value. + /// The serialized value. + public string Value { get; protected set; } + + /// Returns the serialized value. + /// The serialized value. + public override string ToString() + { + return this.Value; + } + } +} diff --git a/src/StripeTests/Infrastructure/FormEncoding/FormEncoderTest.cs b/src/StripeTests/Infrastructure/FormEncoding/FormEncoderTest.cs index 2f43671d32..b479ee2484 100644 --- a/src/StripeTests/Infrastructure/FormEncoding/FormEncoderTest.cs +++ b/src/StripeTests/Infrastructure/FormEncoding/FormEncoderTest.cs @@ -353,6 +353,24 @@ public void CreateQueryString() }, want = "string=" }, + + // StringEnum + new + { + data = new TestOptions + { + StringEnum = TestOptions.TestStringEnum.Foo, + }, + want = "string_enum=foo" + }, + new + { + data = new TestOptions + { + StringEnum = null, + }, + want = string.Empty, + }, }; foreach (var testCase in testCases) diff --git a/src/StripeTests/Infrastructure/TestData/TestOptions.cs b/src/StripeTests/Infrastructure/TestData/TestOptions.cs index 74ac5f1a49..904269c9c8 100644 --- a/src/StripeTests/Infrastructure/TestData/TestOptions.cs +++ b/src/StripeTests/Infrastructure/TestData/TestOptions.cs @@ -57,5 +57,18 @@ public enum TestEnum [JsonProperty("string")] public string String { get; set; } + + [JsonProperty("string_enum")] + public TestStringEnum StringEnum { get; set; } + + public class TestStringEnum : StringEnum + { + public static readonly TestStringEnum Foo = new TestStringEnum("foo"); + + private TestStringEnum(string value) + : base(value) + { + } + } } }