Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make StripeError serializable #2094

Merged
merged 1 commit into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.stripe.android

import android.os.Bundle
import android.os.Parcelable
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 com.stripe.android.view.StripeIntentResultExtras
import kotlinx.android.parcel.Parcelize

/**
* Starts an instance of [PaymentRelayStarter].
Expand Down Expand Up @@ -38,11 +40,12 @@ internal interface PaymentRelayStarter : AuthActivityStarter<PaymentRelayStarter
}
}

@Parcelize
data class Args internal constructor(
val stripeIntent: StripeIntent? = null,
val source: Source? = null,
val exception: Exception? = null
) {
) : Parcelable {
internal companion object {
@JvmSynthetic
internal fun create(stripeIntent: StripeIntent): Args {
Expand Down
3 changes: 2 additions & 1 deletion stripe/src/main/java/com/stripe/android/StripeError.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stripe.android

import com.stripe.android.model.StripeModel
import java.io.Serializable
import kotlinx.android.parcel.Parcelize

/**
Expand Down Expand Up @@ -75,4 +76,4 @@ data class StripeError internal constructor(
* [doc_url](https://stripe.com/docs/api/errors#errors-doc_url)
*/
val docUrl: String? = null
) : StripeModel
) : StripeModel, Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,88 @@ package com.stripe.android

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import com.nhaarman.mockitokotlin2.KArgumentCaptor
import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.eq
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.stripe.android.exception.PermissionException
import com.stripe.android.exception.StripeException
import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.utils.ParcelUtils
import com.stripe.android.view.AuthActivityStarter
import com.stripe.android.view.StripeIntentResultExtras
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class PaymentRelayStarterTest {
@Mock
private lateinit var activity: Activity

private lateinit var intentArgumentCaptor: KArgumentCaptor<Intent>

private lateinit var starter: PaymentRelayStarter

@BeforeTest
fun setup() {
MockitoAnnotations.initMocks(this)
intentArgumentCaptor = argumentCaptor()
starter = PaymentRelayStarter.create(
AuthActivityStarter.Host.create(activity),
500
)
}
private val activity: Activity = mock()
private val intentArgumentCaptor: KArgumentCaptor<Intent> = argumentCaptor()
private val starter: PaymentRelayStarter = PaymentRelayStarter.create(
AuthActivityStarter.Host.create(activity),
500
)

@Test
fun start_withPaymentIntent_shouldSetCorrectIntentExtras() {
starter.start(PaymentRelayStarter.Args.create(PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2))
starter.start(
PaymentRelayStarter.Args.create(PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2)
)
verify(activity).startActivityForResult(intentArgumentCaptor.capture(), eq(500))
val intent = intentArgumentCaptor.firstValue
assertEquals(PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2.clientSecret,
intent.getStringExtra(StripeIntentResultExtras.CLIENT_SECRET))
assertFalse(intent.hasExtra(StripeIntentResultExtras.FLOW_OUTCOME))
assertNull(intent.getSerializableExtra(StripeIntentResultExtras.AUTH_EXCEPTION))
val bundle = ParcelUtils.copy(
intentArgumentCaptor.firstValue.extras ?: Bundle(),
Bundle.CREATOR
)
assertEquals(
PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2.clientSecret,
bundle.getString(StripeIntentResultExtras.CLIENT_SECRET)
)
assertFalse(bundle.containsKey(StripeIntentResultExtras.FLOW_OUTCOME))
assertNull(bundle.getSerializable(StripeIntentResultExtras.AUTH_EXCEPTION))
}

@Test
fun start_withException_shouldSetCorrectIntentExtras() {
val exception = RuntimeException()
starter.start(PaymentRelayStarter.Args.create(exception))
verify(activity).startActivityForResult(intentArgumentCaptor.capture(), eq(500))
val intent = intentArgumentCaptor.firstValue
assertNull(intent.getStringExtra(StripeIntentResultExtras.CLIENT_SECRET))
assertFalse(intent.hasExtra(StripeIntentResultExtras.FLOW_OUTCOME))
assertEquals(exception,
intent.getSerializableExtra(StripeIntentResultExtras.AUTH_EXCEPTION))
val bundle = ParcelUtils.copy(
intentArgumentCaptor.firstValue.extras ?: Bundle(),
Bundle.CREATOR
)
assertNull(bundle.getString(StripeIntentResultExtras.CLIENT_SECRET))
assertFalse(bundle.containsKey(StripeIntentResultExtras.FLOW_OUTCOME))
assertTrue(
bundle.getSerializable(StripeIntentResultExtras.AUTH_EXCEPTION) is RuntimeException
)
}

@Test
fun start_withStripeException_shouldSetCorrectIntentExtras() {
val exception = PermissionException(
stripeError = StripeErrorFixtures.INVALID_REQUEST_ERROR
)
starter.start(PaymentRelayStarter.Args.create(exception))
verify(activity).startActivityForResult(intentArgumentCaptor.capture(), eq(500))
val bundle = ParcelUtils.copy(
intentArgumentCaptor.firstValue.extras ?: Bundle(),
Bundle.CREATOR
)
assertNull(bundle.getString(StripeIntentResultExtras.CLIENT_SECRET))
assertFalse(bundle.containsKey(StripeIntentResultExtras.FLOW_OUTCOME))

val expectedException =
bundle.getSerializable(StripeIntentResultExtras.AUTH_EXCEPTION) as StripeException
assertEquals(
exception.stripeError,
expectedException.stripeError
)
}
}
18 changes: 18 additions & 0 deletions stripe/src/test/java/com/stripe/android/utils/ParcelUtils.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stripe.android.utils

import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable

internal object ParcelUtils {
Expand All @@ -17,5 +18,22 @@ internal object ParcelUtils {
return requireNotNull(bundle.getParcelable(KEY))
}

/**
* @param source the source from which to parcel and unparcel a new object
* @param creator the [Parcelable.Creator]
*
* @return a new [SOURCE] instance based on the original source
*/
@JvmStatic
fun <SOURCE : Parcelable> copy(
source: SOURCE,
creator: Parcelable.Creator<SOURCE>
): SOURCE {
val parcel = Parcel.obtain()
source.writeToParcel(parcel, source.describeContents())
parcel.setDataPosition(0)
return creator.createFromParcel(parcel)
}

private const val KEY = "parcelable"
}