From cefc81cb9eb9fee9ccfc23289caef6ce96ab5f3f Mon Sep 17 00:00:00 2001 From: Josue Date: Tue, 13 Dec 2022 17:31:14 -0600 Subject: [PATCH 1/6] computing cvc mask based on card brand --- .../android/example/view/card/CardFragment.kt | 2 ++ .../android/service/CardBrandEnricher.kt | 31 +++++++++++-------- .../android/view/CardNumberElement.kt | 6 ++++ .../view/CardVerificationCodeElement.kt | 14 +++++++++ .../basistheory/android/view/TextElement.kt | 1 - .../view/CardVerificationCodeElementTests.kt | 20 +++++++++++- 6 files changed, 59 insertions(+), 15 deletions(-) diff --git a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt index 342a27db..feb1c249 100644 --- a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt +++ b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt @@ -25,6 +25,8 @@ class CardFragment : Fragment() { binding.lifecycleOwner = this binding.viewModel = viewModel + binding.cvc.cardNumberElement = binding.cardNumber + binding.tokenizeButton.setOnClickListener { tokenize() } binding.autofillButton.setOnClickListener { autofill() } diff --git a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt index 1b4e0122..4a9f345c 100644 --- a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt +++ b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt @@ -2,13 +2,18 @@ package com.basistheory.android.service import com.basistheory.android.constants.CardBrands -internal class CardBrandEnricher { +class CardBrandEnricher { object CardMasks { const val MASK_4_8_12GAPS_19LENGTH = "#### #### #### #######" const val MASK_4_8_12GAPS_16LENGTH = "#### #### #### ####" } + object CvcMasks { + const val THREE_DIGIT = "###" + const val FOUR_DIGIT = "####" + } + class CardDetails( var brand: String = "", var identifierRanges: List>, @@ -31,7 +36,7 @@ internal class CardBrandEnricher { CardBrands.VISA.label, listOf("4" to null), intArrayOf(16, 18, 19), - "###", + CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), @@ -43,14 +48,14 @@ internal class CardBrandEnricher { "23" to "26", "270" to "271", "2720" to null - ), intArrayOf(16), "###", CardMasks.MASK_4_8_12GAPS_16LENGTH + ), intArrayOf(16), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_16LENGTH ), CardDetails( CardBrands.AMERICAN_EXPRESS.label, listOf( "34" to null, "37" to null - ), intArrayOf(15), "####", "#### ###### #####" + ), intArrayOf(15), CvcMasks.FOUR_DIGIT, "#### ###### #####" ), CardDetails( @@ -58,7 +63,7 @@ internal class CardBrandEnricher { "36" to null, "38" to "39", "300" to "305" - ), intArrayOf(14, 16, 19), "###", "#### ###### #########" + ), intArrayOf(14, 16, 19), CvcMasks.THREE_DIGIT, "#### ###### #########" ), CardDetails( @@ -66,7 +71,7 @@ internal class CardBrandEnricher { "65" to null, "6011" to "39", "644" to "649" - ), intArrayOf(16, 19), "###", CardMasks.MASK_4_8_12GAPS_19LENGTH + ), intArrayOf(16, 19), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), CardDetails( @@ -74,7 +79,7 @@ internal class CardBrandEnricher { "2131" to null, "1800" to "39", "3528" to "3589" - ), intArrayOf(16, 17, 18, 19), "###", CardMasks.MASK_4_8_12GAPS_19LENGTH + ), intArrayOf(16, 17, 18, 19), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), CardDetails( @@ -95,7 +100,7 @@ internal class CardBrandEnricher { "627781" to "627799", "6282" to "6289", "8110" to "8171", - ), intArrayOf(14, 15, 16, 17, 18, 19), "###", CardMasks.MASK_4_8_12GAPS_19LENGTH + ), intArrayOf(14, 15, 16, 17, 18, 19), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), CardDetails( @@ -108,7 +113,7 @@ internal class CardBrandEnricher { "504176" to "506698", "506779" to "508999", "56" to "59", - ), intArrayOf(12, 13, 14, 15, 16, 17, 18, 19), "###", CardMasks.MASK_4_8_12GAPS_19LENGTH + ), intArrayOf(12, 13, 14, 15, 16, 17, 18, 19), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), CardDetails( @@ -138,14 +143,14 @@ internal class CardBrandEnricher { "651652" to "651679", "655000" to "655019", "655021" to "655058", - ), intArrayOf(16), "###", CardMasks.MASK_4_8_12GAPS_16LENGTH + ), intArrayOf(16), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_16LENGTH ), CardDetails( CardBrands.MIR.label, listOf("2200" to "2204"), intArrayOf(16, 17, 18, 19), - "###", + CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_19LENGTH ), @@ -158,13 +163,13 @@ internal class CardBrandEnricher { "637599" to null, "637609" to null, "637612" to null, - ), intArrayOf(16), "###", CardMasks.MASK_4_8_12GAPS_16LENGTH + ), intArrayOf(16), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_16LENGTH ), CardDetails( CardBrands.HIPERCARD.label, listOf( "606282" to null, - ), intArrayOf(16), "###", CardMasks.MASK_4_8_12GAPS_16LENGTH + ), intArrayOf(16), CvcMasks.THREE_DIGIT, CardMasks.MASK_4_8_12GAPS_16LENGTH ) ) diff --git a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt index 8614c414..3ec811f3 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt @@ -14,6 +14,8 @@ class CardNumberElement @JvmOverloads constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0) : TextElement(context, attrs, defStyleAttr) { + var cardDetails: CardBrandEnricher.CardDetails? = null + private val cardBrandEnricher: CardBrandEnricher = CardBrandEnricher() init { @@ -25,6 +27,8 @@ class CardNumberElement @JvmOverloads constructor( override fun beforeTextChanged(value: String?): String? { val cardResult = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) + cardDetails = cardResult.cardDetails + if (cardResult.cardDetails?.cardMask != null) mask = cardResult.cardDetails!!.cardMask.toList() @@ -38,6 +42,8 @@ class CardNumberElement @JvmOverloads constructor( isValid: Boolean ): ChangeEvent { val cardResult = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) + cardDetails = cardResult.cardDetails + val eventDetails = cardResult.cardDetails?.brand?.let { brand -> mutableListOf( EventDetails( diff --git a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt index 660ee834..ae3eeb34 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt @@ -9,6 +9,16 @@ class CardVerificationCodeElement @JvmOverloads constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0) : TextElement(context, attrs, defStyleAttr) { + var cardNumberElement: CardNumberElement? = null + set(value) { + field = value + + if (value != null) { + super.mask = field?.cardDetails?.cvcMask?.toList() ?: defaultMask + field?.addChangeEventListener { updateMask() } + } + } + init { super.keyboardType = KeyboardType.NUMBER super.mask = defaultMask @@ -21,4 +31,8 @@ class CardVerificationCodeElement @JvmOverloads constructor( val defaultMask: List = listOf(digit, digit, digit) } + + private fun updateMask() { + super.mask = cardNumberElement?.cardDetails?.cvcMask?.toList() ?: defaultMask + } } diff --git a/lib/src/main/java/com/basistheory/android/view/TextElement.kt b/lib/src/main/java/com/basistheory/android/view/TextElement.kt index 36a0323b..d7dbc0eb 100644 --- a/lib/src/main/java/com/basistheory/android/view/TextElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/TextElement.kt @@ -23,7 +23,6 @@ import com.basistheory.android.model.InputAction import com.basistheory.android.model.KeyboardType import com.basistheory.android.view.mask.Mask - open class TextElement @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, diff --git a/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt b/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt index 16c05a3f..a10080e6 100644 --- a/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt +++ b/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt @@ -17,10 +17,13 @@ import strikt.assertions.single class CardVerificationCodeElementTests { private lateinit var cvcElement: CardVerificationCodeElement + private lateinit var cardNumberElement: CardNumberElement + @Before fun setUp() { val activity = Robolectric.buildActivity(Activity::class.java).get() cvcElement = CardVerificationCodeElement(activity) + cardNumberElement = CardNumberElement(activity) } @Test @@ -33,11 +36,26 @@ class CardVerificationCodeElementTests { } @Test - fun `applies mask when setting the value`() { + fun `applies default mask when setting the value and no card number element is attached`() { + cvcElement.cardNumberElement = null + cvcElement.setText("1a2b3c") expectThat(cvcElement.getText()).isEqualTo("123") } + @Test + fun `updates mask depending on card brand`() { + cvcElement.cardNumberElement = cardNumberElement + + cardNumberElement.setText("42") + cvcElement.setText("1a2b3c4d5e") + expectThat(cvcElement.getText()).isEqualTo("123") + + cardNumberElement.setText("34") + cvcElement.setText("1a2b3c4d5e") + expectThat(cvcElement.getText()).isEqualTo("1234") + } + @Test fun `ChangeEvent is computed properly for incomplete cvc values`() { val changeEvents = mutableListOf() From 7e4a6ab0a96bc747269f93c5d4ed0c076a3bd830 Mon Sep 17 00:00:00 2001 From: Josue Date: Wed, 14 Dec 2022 13:31:55 -0600 Subject: [PATCH 2/6] making card details set private --- .../main/java/com/basistheory/android/view/CardNumberElement.kt | 1 + .../com/basistheory/android/view/CardVerificationCodeElement.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt index 3ec811f3..729904e7 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt @@ -15,6 +15,7 @@ class CardNumberElement @JvmOverloads constructor( defStyleAttr: Int = 0) : TextElement(context, attrs, defStyleAttr) { var cardDetails: CardBrandEnricher.CardDetails? = null + private set private val cardBrandEnricher: CardBrandEnricher = CardBrandEnricher() diff --git a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt index ae3eeb34..9f74502b 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt @@ -13,7 +13,7 @@ class CardVerificationCodeElement @JvmOverloads constructor( set(value) { field = value - if (value != null) { + if (value != null && cardNumberElement != value) { super.mask = field?.cardDetails?.cvcMask?.toList() ?: defaultMask field?.addChangeEventListener { updateMask() } } From 770c50705124fb841a02dbcaba15753b6568e7d1 Mon Sep 17 00:00:00 2001 From: Josue Date: Wed, 14 Dec 2022 15:07:46 -0600 Subject: [PATCH 3/6] not duplicating card number listeners for cvc multiple sets and only compute card metadata once per change --- .../android/example/view/card/CardFragment.kt | 1 + .../android/service/CardBrandEnricher.kt | 20 ++++++++++++++++--- .../android/view/CardNumberElement.kt | 17 ++++++++-------- .../view/CardVerificationCodeElement.kt | 12 ++++++----- .../view/CardVerificationCodeElementTests.kt | 15 ++++++++++++++ 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt index feb1c249..81619782 100644 --- a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt +++ b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt @@ -59,6 +59,7 @@ class CardFragment : Fragment() { */ private fun setValidationListeners() { binding.cardNumber.addChangeEventListener { + println(it) viewModel.cardNumber.observe(it) } binding.cardExpiration.addChangeEventListener { diff --git a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt index 115b8899..46827244 100644 --- a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt +++ b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt @@ -33,6 +33,13 @@ class CardBrandEnricher { get() = cardDetails?.validLengths?.contains(cardLength) ?: false } + class CardMetadata( + val brand: String?, + val cvcMask: String?, + val cardMask: String?, + val complete: Boolean + ) + private val cardBrands = listOf( CardDetails( CardBrands.VISA.label, @@ -205,8 +212,8 @@ class CardBrandEnricher { ) ) - fun evaluateCard(number: String?): CardResult { - if (number.isNullOrBlank()) return CardResult(null) + fun evaluateCard(number: String?): CardMetadata? { + if (number.isNullOrBlank()) return null var bestMatch = CardResult(null) @@ -222,7 +229,14 @@ class CardBrandEnricher { } } - return bestMatch + return with(bestMatch) { + CardMetadata( + this.cardDetails?.brand, + this.cardDetails?.cvcMask, + this.cardDetails?.cardMask, + this.complete + ) + } } private fun chooseBestMatch( diff --git a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt index ff2e693b..188ed9a5 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt @@ -16,7 +16,7 @@ class CardNumberElement @JvmOverloads constructor( defStyleAttr: Int = 0 ) : TextElement(context, attrs, defStyleAttr) { - var cardDetails: CardBrandEnricher.CardDetails? = null + var cardMetadata: CardBrandEnricher.CardMetadata? = null private set private val cardBrandEnricher: CardBrandEnricher = CardBrandEnricher() @@ -29,11 +29,10 @@ class CardNumberElement @JvmOverloads constructor( } override fun beforeTextChanged(value: String?): String? { - val cardResult = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) - cardDetails = cardResult.cardDetails + cardMetadata = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) - if (cardResult.cardDetails?.cardMask != null) - mask = ElementMask(cardResult.cardDetails!!.cardMask) + if (cardMetadata?.cardMask != null) + mask = ElementMask(cardMetadata!!.cardMask!!) return value } @@ -44,10 +43,10 @@ class CardNumberElement @JvmOverloads constructor( isEmpty: Boolean, isValid: Boolean ): ChangeEvent { - val cardResult = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) - cardDetails = cardResult.cardDetails + val cardMetadata = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) + this.cardMetadata = cardMetadata - val eventDetails = cardResult.cardDetails?.brand?.let { brand -> + val eventDetails = this.cardMetadata?.brand?.let { brand -> mutableListOf( EventDetails( "cardBrand", @@ -57,7 +56,7 @@ class CardNumberElement @JvmOverloads constructor( } ?: mutableListOf() return ChangeEvent( - cardResult.complete, + cardMetadata?.complete ?: false, isEmpty, isValid, eventDetails diff --git a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt index 31004a87..bfcbebc5 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardVerificationCodeElement.kt @@ -14,12 +14,13 @@ class CardVerificationCodeElement @JvmOverloads constructor( var cardNumberElement: CardNumberElement? = null set(value) { - field = value - - if (value != null && cardNumberElement != value) { + if (value != null && cardNumberElement !== value) { + field = value super.mask = - cardNumberElement?.cardDetails?.cvcMask?.let { ElementMask(it) } ?: defaultMask + cardNumberElement?.cardMetadata?.cvcMask?.let { ElementMask(it) } ?: defaultMask field?.addChangeEventListener { updateMask() } + } else { + field = value } } @@ -38,6 +39,7 @@ class CardVerificationCodeElement @JvmOverloads constructor( } private fun updateMask() { - super.mask = cardNumberElement?.cardDetails?.cvcMask?.let { ElementMask(it) } ?: defaultMask + super.mask = + cardNumberElement?.cardMetadata?.cvcMask?.let { ElementMask(it) } ?: defaultMask } } diff --git a/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt b/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt index a10080e6..f699c8ef 100644 --- a/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt +++ b/lib/src/test/java/com/basistheory/android/view/CardVerificationCodeElementTests.kt @@ -2,7 +2,13 @@ package com.basistheory.android.view import android.app.Activity import com.basistheory.android.event.ChangeEvent +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.impl.annotations.SpyK +import io.mockk.junit4.MockKRule +import io.mockk.spyk +import io.mockk.verify import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.robolectric.Robolectric @@ -81,4 +87,13 @@ class CardVerificationCodeElementTests { get { isComplete }.isTrue() } } + + @Test + fun `setting card number element multiple times does not duplicate listeners`() { + val cardNumberElement = spyk(CardNumberElement(Robolectric.buildActivity(Activity::class.java).get())) + cvcElement.cardNumberElement = cardNumberElement + cvcElement.cardNumberElement = cardNumberElement + + verify(exactly = 1) { cardNumberElement.addChangeEventListener(any()) } + } } \ No newline at end of file From 35ed2bf64740a694063b33c0ab55f18f01b7f2b6 Mon Sep 17 00:00:00 2001 From: Josue Date: Wed, 14 Dec 2022 15:34:46 -0600 Subject: [PATCH 4/6] card brand enricher cleanup --- .../android/service/CardBrandEnricher.kt | 38 ++++++++++--------- .../android/service/CardBrandEnricherTests.kt | 20 ++++------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt index 46827244..c96d2da3 100644 --- a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt +++ b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt @@ -21,16 +21,12 @@ class CardBrandEnricher { var identifierRanges: List>, var validLengths: IntArray, var cvcMask: String, - var cardMask: String - ) - - class CardResult( - var cardDetails: CardDetails?, + var cardMask: String, var cardLength: Int = -1, var identifierLength: Int = -1, ) { val complete: Boolean - get() = cardDetails?.validLengths?.contains(cardLength) ?: false + get() = validLengths.contains(cardLength) } class CardMetadata( @@ -215,7 +211,7 @@ class CardBrandEnricher { fun evaluateCard(number: String?): CardMetadata? { if (number.isNullOrBlank()) return null - var bestMatch = CardResult(null) + var bestMatch: CardDetails? = null cardBrands.forEach { cardDetails -> cardDetails.identifierRanges.forEach { range -> @@ -231,24 +227,30 @@ class CardBrandEnricher { return with(bestMatch) { CardMetadata( - this.cardDetails?.brand, - this.cardDetails?.cvcMask, - this.cardDetails?.cardMask, - this.complete + this?.brand, + this?.cvcMask, + this?.cardMask, + this?.complete ?: false ) } } private fun chooseBestMatch( - currentBestMatch: CardResult, + currentBestMatch: CardDetails?, cardDetails: CardDetails, identifierMatch: String, number: String - ): CardResult = - if (currentBestMatch.identifierLength < identifierMatch.length) CardResult( - cardDetails, - number.length, - identifierMatch.length - ) + ): CardDetails? = + if ((currentBestMatch?.identifierLength ?: -1) < identifierMatch.length) with(cardDetails) { + CardDetails( + this.brand, + this.identifierRanges, + this.validLengths, + this.cvcMask, + this.cardMask, + number.length, + identifierMatch.length + ) + } else currentBestMatch } \ No newline at end of file diff --git a/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt b/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt index ab7c74de..adf0bd8a 100644 --- a/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt +++ b/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt @@ -37,7 +37,7 @@ class CardBrandEnricherTests { expectedBrand: String, expectedCardMask: String ) { - with(cardBrandEnricher.evaluateCard(cardNumber).cardDetails) { + with(cardBrandEnricher.evaluateCard(cardNumber)) { expectThat(this?.brand).isEqualTo(expectedBrand) expectThat(this?.cardMask).isEqualTo(expectedCardMask) } @@ -45,7 +45,7 @@ class CardBrandEnricherTests { @Test fun `should pick best match based on identifier length`() { - expectThat(cardBrandEnricher.evaluateCard("4011784867543859").cardDetails?.brand).isEqualTo( + expectThat(cardBrandEnricher.evaluateCard("4011784867543859")?.brand).isEqualTo( "elo" ) } @@ -55,22 +55,18 @@ class CardBrandEnricherTests { // discover valid lengths are 16 or 19 val sixteenDigitsDiscoverCardNumber = "6582937163058334" - expectThat(cardBrandEnricher.evaluateCard(sixteenDigitsDiscoverCardNumber).complete).isTrue() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}1").complete).isFalse() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}12").complete).isFalse() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}123").complete).isTrue() + expectThat(cardBrandEnricher.evaluateCard(sixteenDigitsDiscoverCardNumber)?.complete).isTrue() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}1")?.complete).isFalse() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}12")?.complete).isFalse() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}123")?.complete).isTrue() } @Test fun `should handle null or empty card number`() { val nullCard = cardBrandEnricher.evaluateCard(null) - - expectThat(nullCard.cardDetails).isNull() - expectThat(nullCard.complete).isFalse() + expectThat(nullCard).isNull() val emptyCard = cardBrandEnricher.evaluateCard("") - - expectThat(emptyCard.cardDetails).isNull() - expectThat(emptyCard.complete).isFalse() + expectThat(emptyCard).isNull() } } \ No newline at end of file From 2b3f8f6856dd4f1dd62413e008198c4e9d9b7055 Mon Sep 17 00:00:00 2001 From: Josue Date: Wed, 14 Dec 2022 16:22:07 -0600 Subject: [PATCH 5/6] remove unneeded lines --- .../com/basistheory/android/example/view/card/CardFragment.kt | 1 - .../java/com/basistheory/android/view/CardNumberElement.kt | 3 --- 2 files changed, 4 deletions(-) diff --git a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt index 81619782..feb1c249 100644 --- a/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt +++ b/example/src/main/java/com/basistheory/android/example/view/card/CardFragment.kt @@ -59,7 +59,6 @@ class CardFragment : Fragment() { */ private fun setValidationListeners() { binding.cardNumber.addChangeEventListener { - println(it) viewModel.cardNumber.observe(it) } binding.cardExpiration.addChangeEventListener { diff --git a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt index 188ed9a5..c216c140 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt @@ -43,9 +43,6 @@ class CardNumberElement @JvmOverloads constructor( isEmpty: Boolean, isValid: Boolean ): ChangeEvent { - val cardMetadata = cardBrandEnricher.evaluateCard(getDigitsOnly(value)) - this.cardMetadata = cardMetadata - val eventDetails = this.cardMetadata?.brand?.let { brand -> mutableListOf( EventDetails( From c25fc6030a5b53f37192abd198285bbb5ed2b669 Mon Sep 17 00:00:00 2001 From: Drew Hudec Date: Thu, 15 Dec 2022 09:26:17 -0500 Subject: [PATCH 6/6] Renames complete properties to isComplete to match ChangeEvent --- .../basistheory/android/service/CardBrandEnricher.kt | 6 +++--- .../com/basistheory/android/view/CardNumberElement.kt | 2 +- .../android/service/CardBrandEnricherTests.kt | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt index c96d2da3..95cd8fe9 100644 --- a/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt +++ b/lib/src/main/java/com/basistheory/android/service/CardBrandEnricher.kt @@ -25,7 +25,7 @@ class CardBrandEnricher { var cardLength: Int = -1, var identifierLength: Int = -1, ) { - val complete: Boolean + val isComplete: Boolean get() = validLengths.contains(cardLength) } @@ -33,7 +33,7 @@ class CardBrandEnricher { val brand: String?, val cvcMask: String?, val cardMask: String?, - val complete: Boolean + val isComplete: Boolean ) private val cardBrands = listOf( @@ -230,7 +230,7 @@ class CardBrandEnricher { this?.brand, this?.cvcMask, this?.cardMask, - this?.complete ?: false + this?.isComplete ?: false ) } } diff --git a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt index c216c140..66b00b82 100644 --- a/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt +++ b/lib/src/main/java/com/basistheory/android/view/CardNumberElement.kt @@ -53,7 +53,7 @@ class CardNumberElement @JvmOverloads constructor( } ?: mutableListOf() return ChangeEvent( - cardMetadata?.complete ?: false, + cardMetadata?.isComplete ?: false, isEmpty, isValid, eventDetails diff --git a/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt b/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt index adf0bd8a..c93b1282 100644 --- a/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt +++ b/lib/src/test/java/com/basistheory/android/service/CardBrandEnricherTests.kt @@ -51,14 +51,14 @@ class CardBrandEnricherTests { } @Test - fun `should set complete for best match card lengths`() { + fun `should set isComplete for best match card lengths`() { // discover valid lengths are 16 or 19 val sixteenDigitsDiscoverCardNumber = "6582937163058334" - expectThat(cardBrandEnricher.evaluateCard(sixteenDigitsDiscoverCardNumber)?.complete).isTrue() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}1")?.complete).isFalse() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}12")?.complete).isFalse() - expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}123")?.complete).isTrue() + expectThat(cardBrandEnricher.evaluateCard(sixteenDigitsDiscoverCardNumber)?.isComplete).isTrue() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}1")?.isComplete).isFalse() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}12")?.isComplete).isFalse() + expectThat(cardBrandEnricher.evaluateCard("${sixteenDigitsDiscoverCardNumber}123")?.isComplete).isTrue() } @Test