From 55ef5730f828ff9311544fc15689a79de9a02088 Mon Sep 17 00:00:00 2001 From: Michael Shafrir Date: Fri, 7 Feb 2020 23:23:09 -0500 Subject: [PATCH] Fix parceling of PaymentRelayStarter.Args Summary Write custom parceling logic for `PaymentRelayStarter.Args` so that `@Parcelize` doesn't write the `StripeException` field using `Parcel#writeException()`. Motivation Fixes #2152 Testing Add unit tests --- .../com/stripe/android/PaymentRelayStarter.kt | 48 ++++++++++++++- .../stripe/android/PaymentRelayStarterTest.kt | 59 +++++++++++++++++++ .../com/stripe/android/utils/ParcelUtils.kt | 12 ++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt b/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt index 11a0635dff5..efb723e69bf 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt +++ b/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt @@ -1,11 +1,15 @@ package com.stripe.android +import android.os.Parcel import android.os.Parcelable import com.stripe.android.exception.StripeException +import com.stripe.android.model.PaymentIntent +import com.stripe.android.model.SetupIntent import com.stripe.android.model.Source import com.stripe.android.model.StripeIntent import com.stripe.android.view.AuthActivityStarter import com.stripe.android.view.PaymentRelayActivity +import kotlinx.android.parcel.Parceler import kotlinx.android.parcel.Parcelize /** @@ -40,7 +44,7 @@ internal interface PaymentRelayStarter : AuthActivityStarter { @JvmSynthetic internal fun create(stripeIntent: StripeIntent): Args { return Args(stripeIntent = stripeIntent) @@ -55,6 +59,48 @@ internal interface PaymentRelayStarter : AuthActivityStarter + parcel.readParcelable(PaymentIntent::class.java.classLoader) + StripeIntentType.SetupIntent -> + parcel.readParcelable(SetupIntent::class.java.classLoader) + else -> null + } + } + + private fun writeStripeIntent(parcel: Parcel, stripeIntent: StripeIntent?) { + val stripeIntentType = when (stripeIntent) { + is PaymentIntent -> StripeIntentType.PaymentIntent + is SetupIntent -> StripeIntentType.SetupIntent + else -> StripeIntentType.None + } + parcel.writeInt(stripeIntentType.ordinal) + stripeIntent?.let { + parcel.writeParcelable(it, 0) + } + } + + private enum class StripeIntentType { + None, + PaymentIntent, + SetupIntent + } } } } diff --git a/stripe/src/test/java/com/stripe/android/PaymentRelayStarterTest.kt b/stripe/src/test/java/com/stripe/android/PaymentRelayStarterTest.kt index b0aaba6eeb8..bf9c51dfca2 100644 --- a/stripe/src/test/java/com/stripe/android/PaymentRelayStarterTest.kt +++ b/stripe/src/test/java/com/stripe/android/PaymentRelayStarterTest.kt @@ -8,8 +8,12 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.stripe.android.exception.APIException +import com.stripe.android.exception.InvalidRequestException import com.stripe.android.exception.PermissionException import com.stripe.android.model.PaymentIntentFixtures +import com.stripe.android.model.SetupIntentFixtures +import com.stripe.android.model.SourceFixtures +import com.stripe.android.utils.ParcelUtils.verifyParcelRoundtrip import com.stripe.android.view.AuthActivityStarter import kotlin.test.Test import kotlin.test.assertEquals @@ -75,6 +79,61 @@ class PaymentRelayStarterTest { assertEquals(exception, result.exception) } + @Test + fun testParcel_withPaymentIntent() { + verifyParcelRoundtrip( + PaymentRelayStarter.Args( + stripeIntent = PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2, + source = SourceFixtures.CARD, + exception = InvalidRequestException( + stripeError = StripeErrorFixtures.INVALID_REQUEST_ERROR, + cause = IllegalArgumentException() + ) + ) + ) + } + + @Test + fun testParcel_withSetupIntent() { + verifyParcelRoundtrip( + PaymentRelayStarter.Args( + stripeIntent = SetupIntentFixtures.SI_NEXT_ACTION_REDIRECT, + source = SourceFixtures.CARD, + exception = InvalidRequestException( + stripeError = StripeErrorFixtures.INVALID_REQUEST_ERROR, + cause = IllegalArgumentException() + ) + ) + ) + } + + @Test + fun testParcel_withoutStripeIntent() { + verifyParcelRoundtrip( + PaymentRelayStarter.Args( + stripeIntent = null, + source = SourceFixtures.CARD, + exception = InvalidRequestException( + stripeError = StripeErrorFixtures.INVALID_REQUEST_ERROR, + cause = IllegalArgumentException() + ) + ) + ) + } + + @Test + fun testParcel_withStripeIntentwithoutSource() { + verifyParcelRoundtrip( + PaymentRelayStarter.Args( + stripeIntent = SetupIntentFixtures.SI_NEXT_ACTION_REDIRECT, + exception = InvalidRequestException( + stripeError = StripeErrorFixtures.INVALID_REQUEST_ERROR, + cause = IllegalArgumentException() + ) + ) + ) + } + private val result: PaymentController.Result get() { return requireNotNull( diff --git a/stripe/src/test/java/com/stripe/android/utils/ParcelUtils.kt b/stripe/src/test/java/com/stripe/android/utils/ParcelUtils.kt index 966ceda6461..999acbd6608 100644 --- a/stripe/src/test/java/com/stripe/android/utils/ParcelUtils.kt +++ b/stripe/src/test/java/com/stripe/android/utils/ParcelUtils.kt @@ -3,6 +3,7 @@ package com.stripe.android.utils import android.os.Bundle import android.os.Parcel import android.os.Parcelable +import kotlin.test.assertEquals internal object ParcelUtils { /** @@ -35,5 +36,16 @@ internal object ParcelUtils { return creator.createFromParcel(parcel) } + internal fun verifyParcelRoundtrip(expected: Parcelable) { + val bundle = Bundle().also { + it.putParcelable(KEY, expected) + } + + val actual = copy(bundle, Bundle.CREATOR) + .getParcelable(KEY) + + assertEquals(expected, actual) + } + private const val KEY = "parcelable" }