diff --git a/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs b/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs new file mode 100644 index 00000000..2dca5455 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs @@ -0,0 +1,71 @@ +using NUnit.Framework; +using RevenueCat.SimpleJSON; + +namespace RevenueCat.Tests +{ + public class JsonModelTests + { + [Test] + public void VirtualCurrenciesParsesCurrenciesByCode() + { + var response = JSONNode.Parse( + "{\"all\":{" + + "\"COIN\":{\"balance\":120,\"name\":\"Coins\",\"code\":\"COIN\",\"serverDescription\":\"Earned in game\"}," + + "\"GEM\":{\"balance\":4,\"name\":\"Gems\",\"code\":\"GEM\",\"serverDescription\":null}" + + "}}" + ); + + var virtualCurrencies = new Purchases.VirtualCurrencies(response); + + Assert.That(virtualCurrencies.All.Keys, Is.EquivalentTo(new[] { "COIN", "GEM" })); + Assert.That(virtualCurrencies.All["COIN"].Balance, Is.EqualTo(120)); + Assert.That(virtualCurrencies.All["COIN"].Name, Is.EqualTo("Coins")); + Assert.That(virtualCurrencies.All["COIN"].ServerDescription, Is.EqualTo("Earned in game")); + Assert.That(virtualCurrencies.All["GEM"].Balance, Is.EqualTo(4)); + Assert.That(virtualCurrencies.All["GEM"].ServerDescription, Is.Null); + } + + [Test] + public void SubscriptionPriceSupportsValuesAboveInt32Range() + { + var response = JSONNode.Parse( + "{\"formatted\":\"$4,294.97\",\"amountMicros\":4294970000,\"currencyCode\":\"USD\"}" + ); + + var price = new Purchases.SubscriptionOption.Price(response); + + Assert.That(price.AmountMicros, Is.EqualTo(4294970000L)); + } + + [Test] + public void StoreProductParsesKnownProductCategory() + { + var response = JSONNode.Parse( + "{\"title\":\"Monthly\",\"identifier\":\"monthly\",\"description\":\"Monthly access\"," + + "\"price\":9.99,\"priceString\":\"$9.99\",\"currencyCode\":\"USD\"," + + "\"productCategory\":\"SUBSCRIPTION\"}" + ); + + var product = new Purchases.StoreProduct(response); + + Assert.That(product.ProductCategory, Is.EqualTo(Purchases.ProductCategory.SUBSCRIPTION)); + } + + [Test] + public void StoreProductFallsBackToUnknownProductCategory() + { + var response = JSONNode.Parse( + "{\"title\":\"Lifetime\",\"identifier\":\"lifetime\",\"description\":\"Lifetime access\"," + + "\"price\":99.99,\"priceString\":\"$99.99\",\"currencyCode\":\"USD\"," + + "\"productCategory\":\"UNRECOGNIZED\"}" + ); + + var product = new Purchases.StoreProduct(response); + + Assert.That(product.Identifier, Is.EqualTo("lifetime")); + Assert.That(product.ProductCategory, Is.EqualTo(Purchases.ProductCategory.UNKNOWN)); + Assert.That(product.DefaultOption, Is.Null); + Assert.That(product.Discounts, Is.Null); + } + } +} diff --git a/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs.meta b/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs.meta new file mode 100644 index 00000000..5f35c933 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90c6103250844a23b9bc88e85907bf37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs b/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs new file mode 100644 index 00000000..3354ea50 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using RevenueCat.SimpleJSON; + +namespace RevenueCat.Tests +{ + public class PresentedOfferingContextTests + { + [Test] + public void JsonRoundTripPreservesAllContext() + { + var originalJson = JSONNode.Parse( + "{\"offeringIdentifier\":\"default\",\"placementIdentifier\":\"onboarding\"," + + "\"targetingContext\":{\"revision\":7,\"ruleId\":\"rule-id\"}}" + ); + + var context = new Purchases.PresentedOfferingContext(originalJson); + var serializedContext = JSONNode.Parse(context.ToJsonString()); + + Assert.That(serializedContext["offeringIdentifier"].Value, Is.EqualTo("default")); + Assert.That(serializedContext["placementIdentifier"].Value, Is.EqualTo("onboarding")); + Assert.That(serializedContext["targetingContext"]["revision"].AsInt, Is.EqualTo(7)); + Assert.That(serializedContext["targetingContext"]["ruleId"].Value, Is.EqualTo("rule-id")); + } + + [Test] + public void OfferingIdentifierConstructorOmitsOptionalContext() + { + var context = new Purchases.PresentedOfferingContext("default"); + var serializedContext = JSONNode.Parse(context.ToJsonString()); + + Assert.That(serializedContext["offeringIdentifier"].Value, Is.EqualTo("default")); + Assert.That(serializedContext.HasKey("placementIdentifier"), Is.False); + Assert.That(serializedContext.HasKey("targetingContext"), Is.False); + } + } +} diff --git a/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs.meta b/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs.meta new file mode 100644 index 00000000..bdcb2171 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PresentedOfferingContextTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a3791f9b503416eafacfbd847ecec71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs b/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs new file mode 100644 index 00000000..bb841fe8 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs @@ -0,0 +1,78 @@ +using NUnit.Framework; +using RevenueCat.SimpleJSON; +using UnityEngine; + +namespace RevenueCat.Tests +{ + public class PurchasesCallTests + { + private GameObject _gameObject; + private Purchases _purchases; + private PurchasesWrapperSpy _wrapper; + + [SetUp] + public void SetUp() + { + _gameObject = new GameObject("RevenueCatTests"); + _purchases = _gameObject.AddComponent(); + _wrapper = new PurchasesWrapperSpy(); + _purchases.SetWrapper(_wrapper); + } + + [TearDown] + public void TearDown() + { + Object.DestroyImmediate(_gameObject); + } + + [Test] + public void ConfigureForwardsEveryConfigurationValue() + { + var configuration = Purchases.PurchasesConfiguration.Builder + .Init("test_api_key") + .SetAppUserId("app_user_id") + .SetPurchasesAreCompletedBy(Purchases.PurchasesAreCompletedBy.MyApp, + Purchases.StoreKitVersion.StoreKit2) + .SetUserDefaultsSuiteName("suite_name") + .SetUseAmazon(true) + .SetDangerousSettings(new Purchases.DangerousSettings(false, true)) + .SetShouldShowInAppMessagesAutomatically(true) + .SetEntitlementVerificationMode(Purchases.EntitlementVerificationMode.Informational) + .SetPendingTransactionsForPrepaidPlansEnabled(true) + .SetDiagnosticsEnabled(true) + .SetAutomaticDeviceIdentifierCollectionEnabled(false) + .SetPreferredUILocaleOverride("de_DE") + .Build(); + + _purchases.Configure(configuration); + + var invocation = AssertOnlyInvocation(nameof(IPurchasesWrapper.Setup), 14); + Assert.That(invocation.Arguments[0], Is.EqualTo(_gameObject.name)); + Assert.That(invocation.Arguments[1], Is.EqualTo("test_api_key")); + Assert.That(invocation.Arguments[2], Is.EqualTo("app_user_id")); + Assert.That(invocation.Arguments[3], Is.EqualTo(Purchases.PurchasesAreCompletedBy.MyApp)); + Assert.That(invocation.Arguments[4], Is.EqualTo(Purchases.StoreKitVersion.StoreKit2)); + Assert.That(invocation.Arguments[5], Is.EqualTo("suite_name")); + Assert.That(invocation.Arguments[6], Is.True); + var dangerousSettings = JSONNode.Parse((string)invocation.Arguments[7]); + Assert.That(dangerousSettings["AutoSyncPurchases"].AsBool, Is.False); + Assert.That(dangerousSettings["UseWorkflows"].AsBool, Is.True); + Assert.That(invocation.Arguments[8], Is.True); + Assert.That(invocation.Arguments[9], Is.EqualTo(Purchases.EntitlementVerificationMode.Informational)); + Assert.That(invocation.Arguments[10], Is.True); + Assert.That(invocation.Arguments[11], Is.True); + Assert.That(invocation.Arguments[12], Is.False); + Assert.That(invocation.Arguments[13], Is.EqualTo("de_DE")); + } + + private PurchasesWrapperSpy.Invocation AssertOnlyInvocation(string method, int argumentCount) + { + Assert.That(_wrapper.Invocations, Has.Count.EqualTo(1)); + + var invocation = _wrapper.Invocations[0]; + Assert.That(invocation.Method, Is.EqualTo(method)); + Assert.That(invocation.Arguments, Has.Length.EqualTo(argumentCount)); + return invocation; + } + } +} diff --git a/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs.meta b/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs.meta new file mode 100644 index 00000000..24237f03 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PurchasesCallTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30b46e0ec5314d2b9e881bb88b801d64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs b/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs new file mode 100644 index 00000000..8cf76407 --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs @@ -0,0 +1,79 @@ +using NUnit.Framework; + +namespace RevenueCat.Tests +{ + public class PurchasesConfigurationTests + { + /// + /// These must stay in sync with the inspector defaults on Purchases, so that configuring through + /// runtime setup and configuring through the inspector behave the same when a setter is not called. + /// + [Test] + public void BuildUsesDocumentedDefaults() + { + var configuration = Purchases.PurchasesConfiguration.Builder + .Init("test_api_key") + .Build(); + + Assert.That(configuration.ApiKey, Is.EqualTo("test_api_key")); + Assert.That(configuration.AppUserId, Is.Null); + Assert.That(configuration.PurchasesAreCompletedBy, Is.EqualTo(Purchases.PurchasesAreCompletedBy.RevenueCat)); + Assert.That(configuration.UserDefaultsSuiteName, Is.Null); + Assert.That(configuration.UseAmazon, Is.False); + Assert.That(configuration.DangerousSettings.AutoSyncPurchases, Is.True); + Assert.That(configuration.StoreKitVersion, Is.EqualTo(Purchases.StoreKitVersion.Default)); + Assert.That(configuration.ShouldShowInAppMessagesAutomatically, Is.True); + Assert.That(configuration.EntitlementVerificationMode, Is.EqualTo(Purchases.EntitlementVerificationMode.Informational)); + Assert.That(configuration.PendingTransactionsForPrepaidPlansEnabled, Is.False); + Assert.That(configuration.DiagnosticsEnabled, Is.False); + Assert.That(configuration.AutomaticDeviceIdentifierCollectionEnabled, Is.True); + Assert.That(configuration.PreferredUILocaleOverride, Is.Null); + } + + [Test] + public void BuildUsesConfiguredValues() + { + var dangerousSettings = new Purchases.DangerousSettings(false); + + var configuration = Purchases.PurchasesConfiguration.Builder + .Init("test_api_key") + .SetAppUserId("app_user_id") + .SetPurchasesAreCompletedBy(Purchases.PurchasesAreCompletedBy.MyApp, Purchases.StoreKitVersion.StoreKit2) + .SetUserDefaultsSuiteName("suite_name") + .SetUseAmazon(true) + .SetDangerousSettings(dangerousSettings) + .SetShouldShowInAppMessagesAutomatically(true) + .SetEntitlementVerificationMode(Purchases.EntitlementVerificationMode.Informational) + .SetPendingTransactionsForPrepaidPlansEnabled(true) + .SetDiagnosticsEnabled(true) + .SetAutomaticDeviceIdentifierCollectionEnabled(false) + .SetPreferredUILocaleOverride("de_DE") + .Build(); + + Assert.That(configuration.AppUserId, Is.EqualTo("app_user_id")); + Assert.That(configuration.PurchasesAreCompletedBy, Is.EqualTo(Purchases.PurchasesAreCompletedBy.MyApp)); + Assert.That(configuration.StoreKitVersion, Is.EqualTo(Purchases.StoreKitVersion.StoreKit2)); + Assert.That(configuration.UserDefaultsSuiteName, Is.EqualTo("suite_name")); + Assert.That(configuration.UseAmazon, Is.True); + Assert.That(configuration.DangerousSettings, Is.SameAs(dangerousSettings)); + Assert.That(configuration.ShouldShowInAppMessagesAutomatically, Is.True); + Assert.That(configuration.EntitlementVerificationMode, Is.EqualTo(Purchases.EntitlementVerificationMode.Informational)); + Assert.That(configuration.PendingTransactionsForPrepaidPlansEnabled, Is.True); + Assert.That(configuration.DiagnosticsEnabled, Is.True); + Assert.That(configuration.AutomaticDeviceIdentifierCollectionEnabled, Is.False); + Assert.That(configuration.PreferredUILocaleOverride, Is.EqualTo("de_DE")); + } + + [Test] + public void BuildRestoresDefaultDangerousSettingsWhenSetToNull() + { + var configuration = Purchases.PurchasesConfiguration.Builder + .Init("test_api_key") + .SetDangerousSettings(null) + .Build(); + + Assert.That(configuration.DangerousSettings, Is.Not.Null); + Assert.That(configuration.DangerousSettings.AutoSyncPurchases, Is.True); + } + } +} diff --git a/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs.meta b/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs.meta new file mode 100644 index 00000000..a6a7ac6c --- /dev/null +++ b/IntegrationTests/Assets/Tests/EditMode/PurchasesConfigurationTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6566b7a4beb347cda9e2e33f4924819f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RevenueCat/Scripts/PurchasesConfiguration.cs b/RevenueCat/Scripts/PurchasesConfiguration.cs index 9bfcbbc1..b4f1930c 100644 --- a/RevenueCat/Scripts/PurchasesConfiguration.cs +++ b/RevenueCat/Scripts/PurchasesConfiguration.cs @@ -84,9 +84,9 @@ public class Builder private string _userDefaultsSuiteName; private bool _useAmazon; private DangerousSettings _dangerousSettings; - private StoreKitVersion _storeKitVersion; - private bool _shouldShowInAppMessagesAutomatically; - private EntitlementVerificationMode _entitlementVerificationMode; + private StoreKitVersion _storeKitVersion = StoreKitVersion.Default; + private bool _shouldShowInAppMessagesAutomatically = true; + private EntitlementVerificationMode _entitlementVerificationMode = EntitlementVerificationMode.Informational; private bool _pendingTransactionsForPrepaidPlansEnabled; private bool _diagnosticsEnabled; private bool _automaticDeviceIdentifierCollectionEnabled = true;