From 5956c9b011d25e515853e1e481b091d43ee66785 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Dec 2023 17:02:02 +0100 Subject: [PATCH 1/7] Conforming PaymentMethods to Codable --- Adyen.xcodeproj/project.pbxproj | 4 + Adyen/Core/Core Protocols/PaymentMethod.swift | 4 +- Adyen/Core/Models/ShopperInteraction.swift | 4 +- .../Abstract/AnyPaymentMethod.swift | 112 ++++++ .../Abstract/AnyPaymentMethodDecoder.swift | 326 +++++++++++++----- .../Abstract/PaymentMethods.swift | 152 ++------ .../Payment Methods/BCMCPaymentMethod.swift | 6 +- .../CashAppPaymentMethod.swift | 25 +- .../IssuerListPaymentMethod.swift | 25 +- .../OnlineBankingPaymentMethod.swift | 13 +- .../QiwiWalletPaymentMethod.swift | 32 +- .../StoredBCMCPaymentMethod.swift | 6 +- .../GiftCardConfirmationPaymentMethod.swift | 11 +- .../Adyen Tests/Core/PaymentMethodTests.swift | 45 ++- 14 files changed, 507 insertions(+), 258 deletions(-) create mode 100644 Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index 4a4ab94b14..000a710817 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -154,6 +154,7 @@ 81825CC22AC59C6400F91912 /* XCTestCase+RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CC02AC59C6400F91912 /* XCTestCase+RootViewController.swift */; }; 81825CC42AC59C6C00F91912 /* XCTestCase+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CC32AC59C6C00F91912 /* XCTestCase+Wait.swift */; }; 81825CC52AC59C6C00F91912 /* XCTestCase+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CC32AC59C6C00F91912 /* XCTestCase+Wait.swift */; }; + 81881BCE2B1A0A510020E3F2 /* AnyPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81881BCD2B1A0A510020E3F2 /* AnyPaymentMethod.swift */; }; 81896E852A4DB5F300C532CA /* SearchViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81896E842A4DB5F300C532CA /* SearchViewControllerTests.swift */; }; 8191838E2A53062F008EB61A /* FormAddressItem+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8191838D2A53062F008EB61A /* FormAddressItem+Configuration.swift */; }; 819CC3342B14C53200D2EEE9 /* PaymentMethods+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */; }; @@ -1367,6 +1368,7 @@ 81825CBA2AC59C4000F91912 /* UIViewController+Search.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Search.swift"; sourceTree = ""; }; 81825CC02AC59C6400F91912 /* XCTestCase+RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+RootViewController.swift"; sourceTree = ""; }; 81825CC32AC59C6C00F91912 /* XCTestCase+Wait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Wait.swift"; sourceTree = ""; }; + 81881BCD2B1A0A510020E3F2 /* AnyPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyPaymentMethod.swift; sourceTree = ""; }; 81896E842A4DB5F300C532CA /* SearchViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewControllerTests.swift; sourceTree = ""; }; 8191838D2A53062F008EB61A /* FormAddressItem+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FormAddressItem+Configuration.swift"; sourceTree = ""; }; 819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaymentMethods+Equatable.swift"; sourceTree = ""; }; @@ -3735,6 +3737,7 @@ E746E67327B429DF0076BB71 /* Abstract */ = { isa = PBXGroup; children = ( + 81881BCD2B1A0A510020E3F2 /* AnyPaymentMethod.swift */, F9D5751723799BB0009C18B5 /* AnyPaymentMethodDecoder.swift */, F9D5753023828EBB009C18B5 /* AnyCardPaymentMethod.swift */, E9B36C9C223FDE4F00EAA368 /* PaymentMethods.swift */, @@ -6458,6 +6461,7 @@ E278EB4322AA5EC800497FD5 /* IssuerListPaymentMethod.swift in Sources */, F90FB7BC2446E8C8005BFE0E /* BrowserInfo.swift in Sources */, A0414C1F278C27CF00DF3FE9 /* ACHDirectDebitPaymentMethod.swift in Sources */, + 81881BCE2B1A0A510020E3F2 /* AnyPaymentMethod.swift in Sources */, E787C9D1246E948F00B401E0 /* CoreFonts.swift in Sources */, F9589D032601EE7800E4113F /* FormItemInjector.swift in Sources */, 5A15D5A1264BE1E500A8E3C7 /* PrefilledShopperInformation.swift in Sources */, diff --git a/Adyen/Core/Core Protocols/PaymentMethod.swift b/Adyen/Core/Core Protocols/PaymentMethod.swift index 5f16ac5a44..6221fff8ad 100644 --- a/Adyen/Core/Core Protocols/PaymentMethod.swift +++ b/Adyen/Core/Core Protocols/PaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -7,7 +7,7 @@ import Foundation /// A payment method that is available to use. -public protocol PaymentMethod: Decodable { +public protocol PaymentMethod: Codable { /// A string identifying the type of payment method, such as `"card"`, `"ideal"`, `"applepay"`. var type: PaymentMethodType { get } diff --git a/Adyen/Core/Models/ShopperInteraction.swift b/Adyen/Core/Models/ShopperInteraction.swift index caa3a4f0d3..92c455a9c5 100644 --- a/Adyen/Core/Models/ShopperInteraction.swift +++ b/Adyen/Core/Models/ShopperInteraction.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -7,7 +7,7 @@ import Foundation /// A type of shopper interaction during a payment. -public enum ShopperInteraction: String, Decodable { +public enum ShopperInteraction: String, Codable { /// Indicates the shopper is present during the payment. case shopperPresent = "Ecommerce" diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift new file mode 100644 index 0000000000..d6c6759fab --- /dev/null +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift @@ -0,0 +1,112 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +internal enum AnyPaymentMethod: Codable { + case storedInstant(StoredInstantPaymentMethod) + case storedCard(StoredCardPaymentMethod) + case storedPayPal(StoredPayPalPaymentMethod) + case storedBCMC(StoredBCMCPaymentMethod) + case storedBlik(StoredBLIKPaymentMethod) + case storedAchDirectDebit(StoredACHDirectDebitPaymentMethod) + case storedCashAppPay(StoredCashAppPayPaymentMethod) + + case instant(PaymentMethod) + case card(AnyCardPaymentMethod) + case issuerList(IssuerListPaymentMethod) + case sepaDirectDebit(SEPADirectDebitPaymentMethod) + case bacsDirectDebit(BACSDirectDebitPaymentMethod) + case achDirectDebit(ACHDirectDebitPaymentMethod) + case applePay(ApplePayPaymentMethod) + case qiwiWallet(QiwiWalletPaymentMethod) + case weChatPay(WeChatPayPaymentMethod) + case mbWay(MBWayPaymentMethod) + case blik(BLIKPaymentMethod) + case giftcard(GiftCardPaymentMethod) + case mealVoucher(MealVoucherPaymentMethod) + case doku(DokuPaymentMethod) + case sevenEleven(SevenElevenPaymentMethod) + case econtextStores(EContextPaymentMethod) + case econtextATM(EContextPaymentMethod) + case econtextOnline(EContextPaymentMethod) + case boleto(BoletoPaymentMethod) + case affirm(AffirmPaymentMethod) + case atome(AtomePaymentMethod) + case onlineBanking(OnlineBankingPaymentMethod) + case upi(UPIPaymentMethod) + case cashAppPay(CashAppPayPaymentMethod) + + case none + + internal var value: PaymentMethod? { + switch self { + case let .storedCard(paymentMethod): return paymentMethod + case let .storedPayPal(paymentMethod): return paymentMethod + case let .storedBCMC(paymentMethod): return paymentMethod + case let .instant(paymentMethod): return paymentMethod + case let .storedInstant(paymentMethod): return paymentMethod + case let .storedAchDirectDebit(paymentMethod): return paymentMethod + case let .storedCashAppPay(paymentMethod): return paymentMethod + case let .card(paymentMethod): return paymentMethod + case let .issuerList(paymentMethod): return paymentMethod + case let .sepaDirectDebit(paymentMethod): return paymentMethod + case let .bacsDirectDebit(paymentMethod): return paymentMethod + case let .achDirectDebit(paymentMethod): return paymentMethod + case let .applePay(paymentMethod): return paymentMethod + case let .qiwiWallet(paymentMethod): return paymentMethod + case let .weChatPay(paymentMethod): return paymentMethod + case let .mbWay(paymentMethod): return paymentMethod + case let .blik(paymentMethod): return paymentMethod + case let .storedBlik(paymentMethod): return paymentMethod + case let .doku(paymentMethod): return paymentMethod + case let .giftcard(paymentMethod): return paymentMethod + case let .mealVoucher(paymentMethod): return paymentMethod + case let .sevenEleven(paymentMethod): return paymentMethod + case let .econtextStores(paymentMethod): return paymentMethod + case let .econtextATM(paymentMethod): return paymentMethod + case let .econtextOnline(paymentMethod): return paymentMethod + case let .boleto(paymentMethod): return paymentMethod + case let .affirm(paymentMethod): return paymentMethod + case let .atome(paymentMethod): return paymentMethod + case let .onlineBanking(paymentMethod): return paymentMethod + case let .upi(paymentMethod): return paymentMethod + case let .cashAppPay(paymentMethod): return paymentMethod + case .none: return nil + } + } + + // MARK: - Decoding + + internal init(from decoder: Decoder) throws { + self = AnyPaymentMethodInterpreter.decode(from: decoder) + } + + internal func encode(to encoder: Encoder) throws { + try value?.encode(to: encoder) + } + + internal enum CodingKeys: String, CodingKey { + case type + case details + case brand + case issuers + } +} + +extension AnyPaymentMethod { + + init(_ paymentMethod: PaymentMethod) { + self = AnyPaymentMethodInterpreter.anyPaymentMethod(from: paymentMethod) + } +} + +extension PaymentMethod { + + var toAnyPaymentMethod: AnyPaymentMethod { + .init(self) + } +} diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift index d030477092..94f0bd711c 100644 --- a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift @@ -30,63 +30,64 @@ private struct PaymentMethodField: Decodable { } -internal enum AnyPaymentMethodDecoder { - private static var decoders: [PaymentMethodType: PaymentMethodDecoder] = [ +internal enum AnyPaymentMethodInterpreter { + + private static var interpreters: [PaymentMethodType: PaymentMethodInterpreter] = [ // Unsupported payment methods - .bcmcMobileQR: UnsupportedPaymentMethodDecoder(), - .weChatMiniProgram: UnsupportedPaymentMethodDecoder(), - .weChatQR: UnsupportedPaymentMethodDecoder(), - .weChatPayWeb: UnsupportedPaymentMethodDecoder(), - .googlePay: UnsupportedPaymentMethodDecoder(), - .afterpay: UnsupportedPaymentMethodDecoder(), - .androidPay: UnsupportedPaymentMethodDecoder(), - .amazonPay: UnsupportedPaymentMethodDecoder(), - .bizum: UnsupportedPaymentMethodDecoder(), + .bcmcMobileQR: UnsupportedPaymentMethodInterpreter(), + .weChatMiniProgram: UnsupportedPaymentMethodInterpreter(), + .weChatQR: UnsupportedPaymentMethodInterpreter(), + .weChatPayWeb: UnsupportedPaymentMethodInterpreter(), + .googlePay: UnsupportedPaymentMethodInterpreter(), + .afterpay: UnsupportedPaymentMethodInterpreter(), + .androidPay: UnsupportedPaymentMethodInterpreter(), + .amazonPay: UnsupportedPaymentMethodInterpreter(), + .bizum: UnsupportedPaymentMethodInterpreter(), // Supported payment methods - .card: CardPaymentMethodDecoder(), - .scheme: CardPaymentMethodDecoder(), - .ideal: IssuerListPaymentMethodDecoder(), - .entercash: IssuerListPaymentMethodDecoder(), - .eps: IssuerListPaymentMethodDecoder(), - .dotpay: IssuerListPaymentMethodDecoder(), - .onlineBankingPoland: IssuerListPaymentMethodDecoder(), - .openBankingUK: IssuerListPaymentMethodDecoder(), - .molPayEBankingFPXMY: IssuerListPaymentMethodDecoder(), - .molPayEBankingTH: IssuerListPaymentMethodDecoder(), - .molPayEBankingVN: IssuerListPaymentMethodDecoder(), - .sepaDirectDebit: SEPADirectDebitPaymentMethodDecoder(), - .bacsDirectDebit: BACSDirectDebitPaymentMethodDecoder(), - .achDirectDebit: ACHDirectDebitPaymentMethodDecoder(), - .applePay: ApplePayPaymentMethodDecoder(), - .payPal: PayPalPaymentMethodDecoder(), - .bcmc: BCMCCardPaymentMethodDecoder(), - .weChatPaySDK: WeChatPayPaymentMethodDecoder(), - .qiwiWallet: QiwiWalletPaymentMethodDecoder(), - .mbWay: MBWayPaymentMethodDecoder(), - .blik: BLIKPaymentMethodDecoder(), - .dokuWallet: DokuPaymentMethodDecoder(), - .dokuAlfamart: DokuPaymentMethodDecoder(), - .dokuIndomaret: DokuPaymentMethodDecoder(), - .giftcard: GiftCardPaymentMethodDecoder(), - .mealVoucherSodexo: MealVoucherPaymentMethodDecoder(), - .mealVoucherNatixis: MealVoucherPaymentMethodDecoder(), - .mealVoucherGroupeUp: MealVoucherPaymentMethodDecoder(), - .econtextSevenEleven: SevenElevenPaymentMethodDecoder(), - .econtextStores: EContextStoresPaymentMethodDecoder(), - .econtextATM: EContextATMPaymentMethodDecoder(), - .econtextOnline: EContextOnlinePaymentMethodDecoder(), - .boleto: BoletoPaymentMethodDecoder(), - .affirm: AffirmPaymentMethodDecoder(), - .atome: AtomePaymentMethodDecoder(), - .onlineBankingCZ: OnlineBankingPaymentMethodDecoder(), - .onlineBankingSK: OnlineBankingPaymentMethodDecoder(), - .upi: UPIPaymentMethodDecoder(), - .cashAppPay: CashAppPayPaymentMethodDecoder() + .card: CardPaymentMethodInterpreter(), + .scheme: CardPaymentMethodInterpreter(), + .ideal: IssuerListPaymentMethodInterpreter(), + .entercash: IssuerListPaymentMethodInterpreter(), + .eps: IssuerListPaymentMethodInterpreter(), + .dotpay: IssuerListPaymentMethodInterpreter(), + .onlineBankingPoland: IssuerListPaymentMethodInterpreter(), + .openBankingUK: IssuerListPaymentMethodInterpreter(), + .molPayEBankingFPXMY: IssuerListPaymentMethodInterpreter(), + .molPayEBankingTH: IssuerListPaymentMethodInterpreter(), + .molPayEBankingVN: IssuerListPaymentMethodInterpreter(), + .sepaDirectDebit: SEPADirectDebitPaymentMethodInterpreter(), + .bacsDirectDebit: BACSDirectDebitPaymentMethodInterpreter(), + .achDirectDebit: ACHDirectDebitPaymentMethodInterpreter(), + .applePay: ApplePayPaymentMethodInterpreter(), + .payPal: PayPalPaymentMethodInterpreter(), + .bcmc: BCMCCardPaymentMethodInterpreter(), + .weChatPaySDK: WeChatPayPaymentMethodInterpreter(), + .qiwiWallet: QiwiWalletPaymentMethodInterpreter(), + .mbWay: MBWayPaymentMethodInterpreter(), + .blik: BLIKPaymentMethodInterpreter(), + .dokuWallet: DokuPaymentMethodInterpreter(), + .dokuAlfamart: DokuPaymentMethodInterpreter(), + .dokuIndomaret: DokuPaymentMethodInterpreter(), + .giftcard: GiftCardPaymentMethodInterpreter(), + .mealVoucherSodexo: MealVoucherPaymentMethodInterpreter(), + .mealVoucherNatixis: MealVoucherPaymentMethodInterpreter(), + .mealVoucherGroupeUp: MealVoucherPaymentMethodInterpreter(), + .econtextSevenEleven: SevenElevenPaymentMethodInterpreter(), + .econtextStores: EContextStoresPaymentMethodInterpreter(), + .econtextATM: EContextATMPaymentMethodInterpreter(), + .econtextOnline: EContextOnlinePaymentMethodInterpreter(), + .boleto: BoletoPaymentMethodInterpreter(), + .affirm: AffirmPaymentMethodInterpreter(), + .atome: AtomePaymentMethodInterpreter(), + .onlineBankingCZ: OnlineBankingPaymentMethodInterpreter(), + .onlineBankingSK: OnlineBankingPaymentMethodInterpreter(), + .upi: UPIPaymentMethodInterpreter(), + .cashAppPay: CashAppPayPaymentMethodInterpreter() ] - private static var defaultDecoder: PaymentMethodDecoder = InstantPaymentMethodDecoder() + private static var defaultInterpreter: PaymentMethodInterpreter = InstantPaymentMethodInterpreter() internal static func decode(from decoder: Decoder) -> AnyPaymentMethod { do { @@ -98,9 +99,9 @@ internal enum AnyPaymentMethodDecoder { if isIssuersList { if type == "onlineBanking_CZ" || type == "onlineBanking_SK" { - return try OnlineBankingPaymentMethodDecoder().decode(from: decoder, isStored: isStored) + return try OnlineBankingPaymentMethodInterpreter().decode(from: decoder, isStored: isStored) } - return try IssuerListPaymentMethodDecoder().decode(from: decoder, isStored: isStored) + return try IssuerListPaymentMethodInterpreter().decode(from: decoder, isStored: isStored) } // This is a hack to handle stored Bancontact as a separate @@ -112,22 +113,28 @@ internal enum AnyPaymentMethodDecoder { // This matching struct will be used as the key to the decoders // dictionary. if isStored, brand == "bcmc", type == "scheme" { - return try decoders[.bcmc, default: defaultDecoder].decode(from: decoder, isStored: true) + return try interpreters[.bcmc, default: defaultInterpreter].decode(from: decoder, isStored: true) } - let paymentDecoder = PaymentMethodType(rawValue: type).map { decoders[$0, default: defaultDecoder] } ?? defaultDecoder + let paymentDecoder = PaymentMethodType(rawValue: type).map { interpreters[$0, default: defaultInterpreter] } ?? defaultInterpreter return try paymentDecoder.decode(from: decoder, isStored: isStored) } catch { return .none } } + + internal static func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod { + let paymentDecoder = interpreters[paymentMethod.type] ?? defaultInterpreter + return paymentDecoder.toAnyPaymentMethod(paymentMethod) ?? .instant(paymentMethod) + } } -private protocol PaymentMethodDecoder { +private protocol PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod + func toAnyPaymentMethod(_ paymentMethod: any PaymentMethod) -> AnyPaymentMethod? } -private struct CardPaymentMethodDecoder: PaymentMethodDecoder { +private struct CardPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedCard(StoredCardPaymentMethod(from: decoder)) @@ -135,9 +142,19 @@ private struct CardPaymentMethodDecoder: PaymentMethodDecoder { return try .card(CardPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredCardPaymentMethod { + return .storedCard(method) + } + if let method = paymentMethod as? CardPaymentMethod { + return .card(method) + } + return nil + } } -private struct BCMCCardPaymentMethodDecoder: PaymentMethodDecoder { +private struct BCMCCardPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedBCMC(StoredBCMCPaymentMethod(from: decoder)) @@ -145,27 +162,49 @@ private struct BCMCCardPaymentMethodDecoder: PaymentMethodDecoder { return try .card(BCMCPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredBCMCPaymentMethod { + return .storedBCMC(method) + } + if let method = paymentMethod as? BCMCPaymentMethod { + return .card(method) + } + return nil + } } -private struct IssuerListPaymentMethodDecoder: PaymentMethodDecoder { +private struct IssuerListPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .issuerList(IssuerListPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? IssuerListPaymentMethod).map { .issuerList($0) } + } } -private struct SEPADirectDebitPaymentMethodDecoder: PaymentMethodDecoder { +private struct SEPADirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .sepaDirectDebit(SEPADirectDebitPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? SEPADirectDebitPaymentMethod).map { .sepaDirectDebit($0) } + } } -private struct BACSDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { +private struct BACSDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .bacsDirectDebit(BACSDirectDebitPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? BACSDirectDebitPaymentMethod).map { .bacsDirectDebit($0) } + } } -private struct ACHDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { +private struct ACHDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedAchDirectDebit(StoredACHDirectDebitPaymentMethod(from: decoder)) @@ -173,15 +212,29 @@ private struct ACHDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { return try .achDirectDebit(ACHDirectDebitPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredACHDirectDebitPaymentMethod { + return .storedAchDirectDebit(method) + } + if let method = paymentMethod as? ACHDirectDebitPaymentMethod { + return .achDirectDebit(method) + } + return nil + } } -private struct ApplePayPaymentMethodDecoder: PaymentMethodDecoder { +private struct ApplePayPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .applePay(ApplePayPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? ApplePayPaymentMethod).map { .applePay($0) } + } } -private struct PayPalPaymentMethodDecoder: PaymentMethodDecoder { +private struct PayPalPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedPayPal(StoredPayPalPaymentMethod(from: decoder)) @@ -189,9 +242,19 @@ private struct PayPalPaymentMethodDecoder: PaymentMethodDecoder { return try .instant(InstantPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredPayPalPaymentMethod { + return .storedPayPal(method) + } + if let method = paymentMethod as? InstantPaymentMethod { + return .instant(method) + } + return nil + } } -private struct InstantPaymentMethodDecoder: PaymentMethodDecoder { +private struct InstantPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedInstant(StoredInstantPaymentMethod(from: decoder)) @@ -199,33 +262,59 @@ private struct InstantPaymentMethodDecoder: PaymentMethodDecoder { return try .instant(InstantPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredInstantPaymentMethod { + return .storedInstant(method) + } + if let method = paymentMethod as? InstantPaymentMethod { + return .instant(method) + } + return nil + } } -private struct WeChatPayPaymentMethodDecoder: PaymentMethodDecoder { +private struct WeChatPayPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .weChatPay(WeChatPayPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? WeChatPayPaymentMethod).map { .weChatPay($0) } + } } -private struct UnsupportedPaymentMethodDecoder: PaymentMethodDecoder { +private struct UnsupportedPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { .none } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + nil + } } -private struct QiwiWalletPaymentMethodDecoder: PaymentMethodDecoder { +private struct QiwiWalletPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .qiwiWallet(QiwiWalletPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? QiwiWalletPaymentMethod).map { .qiwiWallet($0) } + } } -private struct MBWayPaymentMethodDecoder: PaymentMethodDecoder { +private struct MBWayPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .mbWay(MBWayPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? MBWayPaymentMethod).map { .mbWay($0) } + } } -private struct BLIKPaymentMethodDecoder: PaymentMethodDecoder { +private struct BLIKPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedBlik(StoredBLIKPaymentMethod(from: decoder)) @@ -233,81 +322,139 @@ private struct BLIKPaymentMethodDecoder: PaymentMethodDecoder { return try .blik(BLIKPaymentMethod(from: decoder)) } } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + if let method = paymentMethod as? StoredBLIKPaymentMethod { + return .storedBlik(method) + } + if let method = paymentMethod as? BLIKPaymentMethod { + return .blik(method) + } + return nil + } } -private struct DokuPaymentMethodDecoder: PaymentMethodDecoder { +private struct DokuPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .doku(DokuPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? DokuPaymentMethod).map { .doku($0) } + } } -private struct GiftCardPaymentMethodDecoder: PaymentMethodDecoder { +private struct GiftCardPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .giftcard(GiftCardPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? GiftCardPaymentMethod).map { .giftcard($0) } + } } -private struct MealVoucherPaymentMethodDecoder: PaymentMethodDecoder { +private struct MealVoucherPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .mealVoucher(MealVoucherPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? MealVoucherPaymentMethod).map { .mealVoucher($0) } + } } -private struct SevenElevenPaymentMethodDecoder: PaymentMethodDecoder { +private struct SevenElevenPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .sevenEleven(SevenElevenPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? SevenElevenPaymentMethod).map { .sevenEleven($0) } + } } -private struct EContextStoresPaymentMethodDecoder: PaymentMethodDecoder { +private struct EContextStoresPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextStores(EContextPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? EContextPaymentMethod).map { .econtextStores($0) } + } } -private struct EContextATMPaymentMethodDecoder: PaymentMethodDecoder { +private struct EContextATMPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextATM(EContextPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? EContextPaymentMethod).map { .econtextATM($0) } + } } -private struct EContextOnlinePaymentMethodDecoder: PaymentMethodDecoder { +private struct EContextOnlinePaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextOnline(EContextPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? EContextPaymentMethod).map { .econtextOnline($0) } + } } -private struct BoletoPaymentMethodDecoder: PaymentMethodDecoder { +private struct BoletoPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .boleto(BoletoPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? BoletoPaymentMethod).map { .boleto($0) } + } } -private struct AffirmPaymentMethodDecoder: PaymentMethodDecoder { +private struct AffirmPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .affirm(AffirmPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? AffirmPaymentMethod).map { .affirm($0) } + } } -private struct AtomePaymentMethodDecoder: PaymentMethodDecoder { +private struct AtomePaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .atome(AtomePaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? AtomePaymentMethod).map { .atome($0) } + } } -private struct OnlineBankingPaymentMethodDecoder: PaymentMethodDecoder { +private struct OnlineBankingPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .onlineBanking(OnlineBankingPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? OnlineBankingPaymentMethod).map { .onlineBanking($0) } + } } -private struct UPIPaymentMethodDecoder: PaymentMethodDecoder { +private struct UPIPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .upi(UPIPaymentMethod(from: decoder)) } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + (paymentMethod as? UPIPaymentMethod).map { .upi($0) } + } } -private struct CashAppPayPaymentMethodDecoder: PaymentMethodDecoder { +private struct CashAppPayPaymentMethodInterpreter: PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { #if canImport(PayKit) if isStored { @@ -319,4 +466,17 @@ private struct CashAppPayPaymentMethodDecoder: PaymentMethodDecoder { return .none #endif } + + func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + #if canImport(PayKit) + if let method = paymentMethod as? StoredCashAppPayPaymentMethod { + return .storedCashAppPay(method) + } + if let method = paymentMethod as? CashAppPayPaymentMethod { + return .cashAppPay(method) + } + #endif + + return nil + } } diff --git a/Adyen/Core/Payment Methods/Abstract/PaymentMethods.swift b/Adyen/Core/Payment Methods/Abstract/PaymentMethods.swift index 8eb1528b28..5fd62a82bd 100644 --- a/Adyen/Core/Payment Methods/Abstract/PaymentMethods.swift +++ b/Adyen/Core/Payment Methods/Abstract/PaymentMethods.swift @@ -12,7 +12,7 @@ import Foundation - SeeAlso: [API Reference](https://docs.adyen.com/api-explorer/#/CheckoutService/latest/post/paymentMethods__section_resParams) */ -public struct PaymentMethods: Decodable { +public struct PaymentMethods: Codable { /// The already paid payment methods, in case of partial payments. public var paid: [PaymentMethod] = [] @@ -147,137 +147,37 @@ public struct PaymentMethods: Decodable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.regular = try container.decode([AnyPaymentMethod].self, forKey: .regular).compactMap(\.value) - if try container.containsValue(.stored) { - self.stored = try container.decode([AnyPaymentMethod].self, forKey: .stored).compactMap { $0.value as? StoredPaymentMethod } - } else { - self.stored = [] - } - } - - internal enum CodingKeys: String, CodingKey { - case regular = "paymentMethods" - case stored = "storedPaymentMethods" + self.regular = try container.decode( + [AnyPaymentMethod].self, + forKey: .regular + ).compactMap(\.value) + + self.stored = try container.decodeIfPresent( + [AnyPaymentMethod].self, + forKey: .stored + )?.compactMap { + $0.value as? StoredPaymentMethod + } ?? [] } -} + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) -internal enum AnyPaymentMethod: Decodable { - case storedInstant(StoredInstantPaymentMethod) - case storedCard(StoredCardPaymentMethod) - case storedPayPal(StoredPayPalPaymentMethod) - case storedBCMC(StoredBCMCPaymentMethod) - case storedBlik(StoredBLIKPaymentMethod) - case storedAchDirectDebit(StoredACHDirectDebitPaymentMethod) - case storedCashAppPay(StoredCashAppPayPaymentMethod) - - case instant(PaymentMethod) - case card(AnyCardPaymentMethod) - case issuerList(IssuerListPaymentMethod) - case sepaDirectDebit(SEPADirectDebitPaymentMethod) - case bacsDirectDebit(BACSDirectDebitPaymentMethod) - case achDirectDebit(ACHDirectDebitPaymentMethod) - case applePay(ApplePayPaymentMethod) - case qiwiWallet(QiwiWalletPaymentMethod) - case weChatPay(WeChatPayPaymentMethod) - case mbWay(MBWayPaymentMethod) - case blik(BLIKPaymentMethod) - case giftcard(GiftCardPaymentMethod) - case mealVoucher(MealVoucherPaymentMethod) - case doku(DokuPaymentMethod) - case sevenEleven(SevenElevenPaymentMethod) - case econtextStores(EContextPaymentMethod) - case econtextATM(EContextPaymentMethod) - case econtextOnline(EContextPaymentMethod) - case boleto(BoletoPaymentMethod) - case affirm(AffirmPaymentMethod) - case atome(AtomePaymentMethod) - case onlineBanking(OnlineBankingPaymentMethod) - case upi(UPIPaymentMethod) - case cashAppPay(CashAppPayPaymentMethod) - - case none - - internal var value: PaymentMethod? { - switch self { - case let .storedCard(paymentMethod): - return paymentMethod - case let .storedPayPal(paymentMethod): - return paymentMethod - case let .storedBCMC(paymentMethod): - return paymentMethod - case let .instant(paymentMethod): - return paymentMethod - case let .storedInstant(paymentMethod): - return paymentMethod - case let .storedAchDirectDebit(paymentMethod): - return paymentMethod - case let .storedCashAppPay(paymentMethod): - return paymentMethod - case let .card(paymentMethod): - return paymentMethod - case let .issuerList(paymentMethod): - return paymentMethod - case let .sepaDirectDebit(paymentMethod): - return paymentMethod - case let .bacsDirectDebit(paymentMethod): - return paymentMethod - case let .achDirectDebit(paymentMethod): - return paymentMethod - case let .applePay(paymentMethod): - return paymentMethod - case let .qiwiWallet(paymentMethod): - return paymentMethod - case let .weChatPay(paymentMethod): - return paymentMethod - case let .mbWay(paymentMethod): - return paymentMethod - case let .blik(paymentMethod): - return paymentMethod - case let .storedBlik(paymentMethod): - return paymentMethod - case let .doku(paymentMethod): - return paymentMethod - case let .giftcard(paymentMethod): - return paymentMethod - case let .mealVoucher(paymentMethod): - return paymentMethod - case let .sevenEleven(paymentMethod): - return paymentMethod - case let .econtextStores(paymentMethod): - return paymentMethod - case let .econtextATM(paymentMethod): - return paymentMethod - case let .econtextOnline(paymentMethod): - return paymentMethod - case let .boleto(paymentMethod): - return paymentMethod - case let .affirm(paymentMethod): - return paymentMethod - case let .atome(paymentMethod): - return paymentMethod - case let .onlineBanking(paymentMethod): - return paymentMethod - case let .upi(paymentMethod): - return paymentMethod - case let .cashAppPay(paymentMethod): - return paymentMethod - case .none: - return nil - } - } - - // MARK: - Decoding - - internal init(from decoder: Decoder) throws { - self = AnyPaymentMethodDecoder.decode(from: decoder) + try container.encode( + regular.map(\.toAnyPaymentMethod), + forKey: .regular + ) + + try container.encode( + stored.map(\.toAnyPaymentMethod), + forKey: .stored + ) } internal enum CodingKeys: String, CodingKey { - case type - case details - case brand - case issuers + case regular = "paymentMethods" + case stored = "storedPaymentMethods" } + } diff --git a/Adyen/Core/Payment Methods/BCMCPaymentMethod.swift b/Adyen/Core/Payment Methods/BCMCPaymentMethod.swift index 8a9d805e67..909125d7d8 100644 --- a/Adyen/Core/Payment Methods/BCMCPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/BCMCPaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -36,6 +36,10 @@ public struct BCMCPaymentMethod: AnyCardPaymentMethod { self.init(cardPaymentMethod: cardPaymentMethod) } + public func encode(to encoder: Encoder) throws { + try cardPaymentMethod.encode(to: encoder) + } + @_spi(AdyenInternal) public func buildComponent(using builder: PaymentComponentBuilder) -> PaymentComponent? { builder.build(paymentMethod: self) diff --git a/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift b/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift index 0166417ef7..e7acbd887d 100644 --- a/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift @@ -26,11 +26,24 @@ public struct CashAppPayPaymentMethod: PaymentMethod { self.type = try container.decode(PaymentMethodType.self, forKey: .type) self.name = try container.decode(String.self, forKey: .name) - let configuration = try container.nestedContainer(keyedBy: ConfigurationCodingKeys.self, forKey: .configuration) + let configuration = try container.nestedContainer(keyedBy: CodingKeys.Configuration.self, forKey: .configuration) self.clientId = try configuration.decode(String.self, forKey: .clientId) self.scopeId = try configuration.decode(String.self, forKey: .scopeId) } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + // TODO: Write a test for this! + + try container.encode(type, forKey: .type) + try container.encode(name, forKey: .name) + + var configuration = container.nestedContainer(keyedBy: CodingKeys.Configuration.self, forKey: .configuration) + try configuration.encode(clientId, forKey: .clientId) + try configuration.encode(scopeId, forKey: .scopeId) + } + @_spi(AdyenInternal) public func buildComponent(using builder: PaymentComponentBuilder) -> PaymentComponent? { builder.build(paymentMethod: self) @@ -42,10 +55,10 @@ public struct CashAppPayPaymentMethod: PaymentMethod { case type case name case configuration - } - - private enum ConfigurationCodingKeys: String, CodingKey { - case clientId - case scopeId + + enum Configuration: String, CodingKey { + case clientId + case scopeId + } } } diff --git a/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift b/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift index 27961b6e08..ea227a8733 100644 --- a/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -31,9 +31,9 @@ public struct IssuerListPaymentMethod: PaymentMethod { var issuers = [Issuer]() while !detailsContainer.isAtEnd { - let detailContainer = try detailsContainer.nestedContainer(keyedBy: CodingKeys.self) + let detailContainer = try detailsContainer.nestedContainer(keyedBy: CodingKeys.Details.self) let detailKey = try detailContainer.decode(String.self, forKey: .key) - guard detailKey == "issuer" else { + guard detailKey == CodingKeys.Details.issuerKey else { continue } @@ -46,6 +46,13 @@ public struct IssuerListPaymentMethod: PaymentMethod { } } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(type, forKey: .type) + try container.encode(name, forKey: .name) + try container.encode(issuers, forKey: .issuers) + } + @_spi(AdyenInternal) public func buildComponent(using builder: PaymentComponentBuilder) -> PaymentComponent? { builder.build(paymentMethod: self) @@ -54,10 +61,16 @@ public struct IssuerListPaymentMethod: PaymentMethod { private enum CodingKeys: String, CodingKey { case type case name - case details - case key - case items case issuers + + case details + + enum Details: String, CodingKey { + case key + case items + + static var issuerKey: String { "issuer" } + } } } diff --git a/Adyen/Core/Payment Methods/OnlineBankingPaymentMethod.swift b/Adyen/Core/Payment Methods/OnlineBankingPaymentMethod.swift index 83599a2566..ea8af70e7a 100644 --- a/Adyen/Core/Payment Methods/OnlineBankingPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/OnlineBankingPaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -7,7 +7,7 @@ import Foundation /// An issuer (typically a bank) in an issuer list payment method. -public struct Issuer: Decodable, CustomStringConvertible, Equatable { +public struct Issuer: Codable, CustomStringConvertible, Equatable { /// The unique identifier of the issuer. public let identifier: String @@ -40,15 +40,6 @@ public struct OnlineBankingPaymentMethod: PaymentMethod { /// The available issuers. public let issuers: [Issuer] - // MARK: - Coding - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.type = try container.decode(PaymentMethodType.self, forKey: .type) - self.name = try container.decode(String.self, forKey: .name) - self.issuers = try container.decode([Issuer].self, forKey: .issuers) - } - @_spi(AdyenInternal) public func buildComponent(using builder: PaymentComponentBuilder) -> PaymentComponent? { builder.build(paymentMethod: self) diff --git a/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift b/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift index 68acfb19e0..143d654d8d 100644 --- a/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -37,9 +37,9 @@ public struct QiwiWalletPaymentMethod: PaymentMethod { var phoneExtensions: [PhoneExtension]? if var detailsContainer = try? container.nestedUnkeyedContainer(forKey: .details) { while !detailsContainer.isAtEnd { - let detailContainer = try detailsContainer.nestedContainer(keyedBy: CodingKeys.self) + let detailContainer = try detailsContainer.nestedContainer(keyedBy: CodingKeys.Details.self) let detailKey = try detailContainer.decode(String.self, forKey: .key) - guard detailKey == "qiwiwallet.telephoneNumberPrefix" else { continue } + guard detailKey == CodingKeys.Details.phoneExtensionsKey else { continue } phoneExtensions = try detailContainer.decode([PhoneExtension].self, forKey: .items) } @@ -48,6 +48,21 @@ public struct QiwiWalletPaymentMethod: PaymentMethod { self.phoneExtensions = phoneExtensions ?? PhoneExtensionsRepository.get(with: PhoneExtensionsQuery(paymentMethod: .qiwiWallet)) } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + // TODO: Write a test for this! + + try container.encode(type, forKey: .type) + try container.encode(name, forKey: .name) + + var detailsContainer = container.nestedUnkeyedContainer(forKey: .details) + var nested = detailsContainer.nestedContainer(keyedBy: CodingKeys.Details.self) + + try nested.encode(CodingKeys.Details.phoneExtensionsKey, forKey: .key) + try nested.encode(phoneExtensions, forKey: .items) + } + @_spi(AdyenInternal) public func buildComponent(using builder: PaymentComponentBuilder) -> PaymentComponent? { builder.build(paymentMethod: self) @@ -57,13 +72,18 @@ public struct QiwiWalletPaymentMethod: PaymentMethod { case type case name case details - case key - case items + + enum Details: String, CodingKey { + case key + case items + + static var phoneExtensionsKey: String { "qiwiwallet.telephoneNumberPrefix" } + } } } /// Describes a country phone extension. -public struct PhoneExtension: Decodable, Equatable { +public struct PhoneExtension: Codable, Equatable { /// The phone extension. public let value: String diff --git a/Adyen/Core/Payment Methods/StoredBCMCPaymentMethod.swift b/Adyen/Core/Payment Methods/StoredBCMCPaymentMethod.swift index 8e2009ddca..de08250a46 100644 --- a/Adyen/Core/Payment Methods/StoredBCMCPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/StoredBCMCPaymentMethod.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2023 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -56,4 +56,8 @@ public struct StoredBCMCPaymentMethod: StoredPaymentMethod { self.storedCardPaymentMethod = try StoredCardPaymentMethod(from: decoder) } + public func encode(to encoder: Encoder) throws { + try storedCardPaymentMethod.encode(to: encoder) + } + } diff --git a/AdyenCard/Components/GiftCardComponent/GiftCardConfirmationPaymentMethod.swift b/AdyenCard/Components/GiftCardComponent/GiftCardConfirmationPaymentMethod.swift index 35736ad509..3966240a79 100644 --- a/AdyenCard/Components/GiftCardComponent/GiftCardConfirmationPaymentMethod.swift +++ b/AdyenCard/Components/GiftCardComponent/GiftCardConfirmationPaymentMethod.swift @@ -60,13 +60,14 @@ internal struct PartialConfirmationPaymentMethod: PaymentMethod { } internal init(from decoder: Decoder) throws { + // We have to conform to Codable because `PaymentMethod` requires it + // but this struct should never be encoded/decoded as it's an intermediate state fatalError("This class should never be decoded.") } - // MARK: - Decoding - - private enum CodingKeys: String, CodingKey { - case type - case name + internal func encode(to encoder: Encoder) throws { + // We have to conform to Codable because `PaymentMethod` requires it + // but this struct should never be encoded/decoded as it's an intermediate state + fatalError("This class should never be encoded.") } } diff --git a/Tests/Adyen Tests/Core/PaymentMethodTests.swift b/Tests/Adyen Tests/Core/PaymentMethodTests.swift index 1da6ce7b24..2a290f6160 100644 --- a/Tests/Adyen Tests/Core/PaymentMethodTests.swift +++ b/Tests/Adyen Tests/Core/PaymentMethodTests.swift @@ -10,14 +10,8 @@ import XCTest class PaymentMethodTests: XCTestCase { - var paymentMethods: PaymentMethods! - - override func setUpWithError() throws { - paymentMethods = try getPaymentMethods() - } - - private func getPaymentMethods() throws -> PaymentMethods { - let dictionary = [ + private var paymentMethodsDictionary: [String: Any] { + [ "storedPaymentMethods": [ storedCreditCardDictionary, storedCreditCardDictionary, @@ -78,12 +72,28 @@ class PaymentMethodTests: XCTestCase { bizum ] ] - return try AdyenCoder.decode(dictionary) as PaymentMethods + } + + private func getPaymentMethods() throws -> PaymentMethods { + return try AdyenCoder.decode(paymentMethodsDictionary) as PaymentMethods + } + + func testEncodingPaymentMethods() throws { + + let paymentMethods = try getPaymentMethods() + let encodedPaymentMethods = try JSONEncoder().encode(paymentMethods) + let decodedPaymentMethods = try JSONDecoder().decode(PaymentMethods.self, from: encodedPaymentMethods) + + XCTAssertEqual(paymentMethods, decodedPaymentMethods) + + // TODO: Write more tests } func testDecodingPaymentMethods() throws { // Stored payment methods + let paymentMethods = try getPaymentMethods() + XCTAssertEqual(paymentMethods.stored.count, 8) XCTAssertTrue(paymentMethods.stored[0] is StoredCardPaymentMethod) @@ -267,6 +277,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .scheme, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -276,6 +287,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationBCMC() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .bcmc, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -285,6 +297,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationApplePay() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .applePay, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -294,6 +307,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationPayPal() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .payPal, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -303,6 +317,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationWeChat() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .weChatPaySDK, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -312,6 +327,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationQiwiWallet() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .qiwiWallet, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -321,6 +337,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationBLIK() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .blik, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -330,6 +347,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationStoredBLIK() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofStoredPaymentMethod: .blik, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -339,6 +357,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationStoredCreditCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofStoredPaymentMethod: .scheme, with: .init(title: "custom title", subtitle: "custom subtitle"), @@ -357,6 +376,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationStoredDebitCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofStoredPaymentMethod: .scheme, with: .init(title: "custom title", subtitle: "custom subtitle"), @@ -375,6 +395,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationGiro() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .other("giropay"), with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -384,6 +405,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationGenericGiftCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation( ofRegularPaymentMethod: .giftcard, with: .init(title: "custom title", @@ -408,6 +430,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationGivexGiftCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation( ofRegularPaymentMethod: .giftcard, with: .init(title: "custom title", @@ -436,6 +459,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationAnyGivenGiftCard() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation( ofRegularPaymentMethod: .giftcard, with: .init(title: "custom title", @@ -464,6 +488,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationMealVoucher() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .mealVoucherSodexo, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -474,6 +499,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationDukoWallet() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .dokuWallet, with: .init(title: "custom title", subtitle: "custom subtitle")) @@ -483,6 +509,7 @@ class PaymentMethodTests: XCTestCase { } func testOverridingDisplayInformationIdeal() throws { + var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .ideal, with: .init(title: "custom title", subtitle: "custom subtitle")) From 9878dab037469997c02819167953f0b474269a0e Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Dec 2023 17:10:21 +0100 Subject: [PATCH 2/7] Renaming --- .../Abstract/AnyPaymentMethodDecoder.swift | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift index 94f0bd711c..45a3a14d47 100644 --- a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift @@ -116,7 +116,10 @@ internal enum AnyPaymentMethodInterpreter { return try interpreters[.bcmc, default: defaultInterpreter].decode(from: decoder, isStored: true) } - let paymentDecoder = PaymentMethodType(rawValue: type).map { interpreters[$0, default: defaultInterpreter] } ?? defaultInterpreter + let paymentDecoder = PaymentMethodType(rawValue: type).map { + interpreters[$0, default: defaultInterpreter] + } ?? defaultInterpreter + return try paymentDecoder.decode(from: decoder, isStored: isStored) } catch { return .none @@ -125,13 +128,13 @@ internal enum AnyPaymentMethodInterpreter { internal static func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod { let paymentDecoder = interpreters[paymentMethod.type] ?? defaultInterpreter - return paymentDecoder.toAnyPaymentMethod(paymentMethod) ?? .instant(paymentMethod) + return paymentDecoder.anyPaymentMethod(from: paymentMethod) ?? .instant(paymentMethod) } } private protocol PaymentMethodInterpreter { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod - func toAnyPaymentMethod(_ paymentMethod: any PaymentMethod) -> AnyPaymentMethod? + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? } private struct CardPaymentMethodInterpreter: PaymentMethodInterpreter { @@ -143,7 +146,7 @@ private struct CardPaymentMethodInterpreter: PaymentMethodInterpreter { } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredCardPaymentMethod { return .storedCard(method) } @@ -163,7 +166,7 @@ private struct BCMCCardPaymentMethodInterpreter: PaymentMethodInterpreter { } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredBCMCPaymentMethod { return .storedBCMC(method) } @@ -179,7 +182,7 @@ private struct IssuerListPaymentMethodInterpreter: PaymentMethodInterpreter { try .issuerList(IssuerListPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? IssuerListPaymentMethod).map { .issuerList($0) } } } @@ -189,7 +192,7 @@ private struct SEPADirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter try .sepaDirectDebit(SEPADirectDebitPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? SEPADirectDebitPaymentMethod).map { .sepaDirectDebit($0) } } } @@ -199,7 +202,7 @@ private struct BACSDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter try .bacsDirectDebit(BACSDirectDebitPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? BACSDirectDebitPaymentMethod).map { .bacsDirectDebit($0) } } } @@ -213,7 +216,7 @@ private struct ACHDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredACHDirectDebitPaymentMethod { return .storedAchDirectDebit(method) } @@ -229,7 +232,7 @@ private struct ApplePayPaymentMethodInterpreter: PaymentMethodInterpreter { try .applePay(ApplePayPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? ApplePayPaymentMethod).map { .applePay($0) } } } @@ -243,7 +246,7 @@ private struct PayPalPaymentMethodInterpreter: PaymentMethodInterpreter { } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredPayPalPaymentMethod { return .storedPayPal(method) } @@ -263,7 +266,7 @@ private struct InstantPaymentMethodInterpreter: PaymentMethodInterpreter { } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredInstantPaymentMethod { return .storedInstant(method) } @@ -279,7 +282,7 @@ private struct WeChatPayPaymentMethodInterpreter: PaymentMethodInterpreter { try .weChatPay(WeChatPayPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? WeChatPayPaymentMethod).map { .weChatPay($0) } } } @@ -289,7 +292,7 @@ private struct UnsupportedPaymentMethodInterpreter: PaymentMethodInterpreter { .none } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { nil } } @@ -299,7 +302,7 @@ private struct QiwiWalletPaymentMethodInterpreter: PaymentMethodInterpreter { try .qiwiWallet(QiwiWalletPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? QiwiWalletPaymentMethod).map { .qiwiWallet($0) } } } @@ -309,7 +312,7 @@ private struct MBWayPaymentMethodInterpreter: PaymentMethodInterpreter { try .mbWay(MBWayPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? MBWayPaymentMethod).map { .mbWay($0) } } } @@ -323,7 +326,7 @@ private struct BLIKPaymentMethodInterpreter: PaymentMethodInterpreter { } } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredBLIKPaymentMethod { return .storedBlik(method) } @@ -339,7 +342,7 @@ private struct DokuPaymentMethodInterpreter: PaymentMethodInterpreter { try .doku(DokuPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? DokuPaymentMethod).map { .doku($0) } } } @@ -349,7 +352,7 @@ private struct GiftCardPaymentMethodInterpreter: PaymentMethodInterpreter { try .giftcard(GiftCardPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? GiftCardPaymentMethod).map { .giftcard($0) } } } @@ -359,7 +362,7 @@ private struct MealVoucherPaymentMethodInterpreter: PaymentMethodInterpreter { try .mealVoucher(MealVoucherPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? MealVoucherPaymentMethod).map { .mealVoucher($0) } } } @@ -369,7 +372,7 @@ private struct SevenElevenPaymentMethodInterpreter: PaymentMethodInterpreter { try .sevenEleven(SevenElevenPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? SevenElevenPaymentMethod).map { .sevenEleven($0) } } } @@ -379,7 +382,7 @@ private struct EContextStoresPaymentMethodInterpreter: PaymentMethodInterpreter try .econtextStores(EContextPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextStores($0) } } } @@ -389,7 +392,7 @@ private struct EContextATMPaymentMethodInterpreter: PaymentMethodInterpreter { try .econtextATM(EContextPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextATM($0) } } } @@ -399,7 +402,7 @@ private struct EContextOnlinePaymentMethodInterpreter: PaymentMethodInterpreter try .econtextOnline(EContextPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextOnline($0) } } } @@ -409,7 +412,7 @@ private struct BoletoPaymentMethodInterpreter: PaymentMethodInterpreter { try .boleto(BoletoPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? BoletoPaymentMethod).map { .boleto($0) } } } @@ -419,7 +422,7 @@ private struct AffirmPaymentMethodInterpreter: PaymentMethodInterpreter { try .affirm(AffirmPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? AffirmPaymentMethod).map { .affirm($0) } } } @@ -429,7 +432,7 @@ private struct AtomePaymentMethodInterpreter: PaymentMethodInterpreter { try .atome(AtomePaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? AtomePaymentMethod).map { .atome($0) } } } @@ -439,7 +442,7 @@ private struct OnlineBankingPaymentMethodInterpreter: PaymentMethodInterpreter { try .onlineBanking(OnlineBankingPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? OnlineBankingPaymentMethod).map { .onlineBanking($0) } } } @@ -449,7 +452,7 @@ private struct UPIPaymentMethodInterpreter: PaymentMethodInterpreter { try .upi(UPIPaymentMethod(from: decoder)) } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? UPIPaymentMethod).map { .upi($0) } } } @@ -467,7 +470,7 @@ private struct CashAppPayPaymentMethodInterpreter: PaymentMethodInterpreter { #endif } - func toAnyPaymentMethod(_ paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { #if canImport(PayKit) if let method = paymentMethod as? StoredCashAppPayPaymentMethod { return .storedCashAppPay(method) From eb8964dd9f30e59823d1d6b1cd821d0ae667d601 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 4 Dec 2023 11:54:26 +0100 Subject: [PATCH 3/7] Adding coding tests --- .../CashAppPaymentMethod.swift | 2 - .../QiwiWalletPaymentMethod.swift | 2 - .../Adyen Tests/Core/PaymentMethodTests.swift | 65 +++++++++++++++++-- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift b/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift index e7acbd887d..85d1268131 100644 --- a/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/CashAppPaymentMethod.swift @@ -34,8 +34,6 @@ public struct CashAppPayPaymentMethod: PaymentMethod { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - // TODO: Write a test for this! - try container.encode(type, forKey: .type) try container.encode(name, forKey: .name) diff --git a/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift b/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift index 143d654d8d..6fddd5fec1 100644 --- a/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/QiwiWalletPaymentMethod.swift @@ -51,8 +51,6 @@ public struct QiwiWalletPaymentMethod: PaymentMethod { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - // TODO: Write a test for this! - try container.encode(type, forKey: .type) try container.encode(name, forKey: .name) diff --git a/Tests/Adyen Tests/Core/PaymentMethodTests.swift b/Tests/Adyen Tests/Core/PaymentMethodTests.swift index 2a290f6160..7fd9d08526 100644 --- a/Tests/Adyen Tests/Core/PaymentMethodTests.swift +++ b/Tests/Adyen Tests/Core/PaymentMethodTests.swift @@ -78,15 +78,15 @@ class PaymentMethodTests: XCTestCase { return try AdyenCoder.decode(paymentMethodsDictionary) as PaymentMethods } - func testEncodingPaymentMethods() throws { + // MARK: - Payment Methods + + func testPaymentMethodsCoding() throws { + let paymentMethods: PaymentMethods = try getPaymentMethods() - let paymentMethods = try getPaymentMethods() - let encodedPaymentMethods = try JSONEncoder().encode(paymentMethods) - let decodedPaymentMethods = try JSONDecoder().decode(PaymentMethods.self, from: encodedPaymentMethods) + let encodedPaymentMethods: Data = try AdyenCoder.encode(paymentMethods) + let decodedPaymentMethods: PaymentMethods = try AdyenCoder.decode(encodedPaymentMethods) XCTAssertEqual(paymentMethods, decodedPaymentMethods) - - // TODO: Write more tests } func testDecodingPaymentMethods() throws { @@ -276,6 +276,8 @@ class PaymentMethodTests: XCTestCase { } + // MARK: - Display Information Override + func testOverridingDisplayInformationCard() throws { var paymentMethods = try getPaymentMethods() paymentMethods.overrideDisplayInformation(ofRegularPaymentMethod: .scheme, @@ -517,6 +519,8 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(idealPaymentMethod?.displayInformation(using: nil).title, "custom title") XCTAssertEqual(idealPaymentMethod?.displayInformation(using: nil).subtitle, "custom subtitle") } + + // MARK: - Misc func testDecodingPaymentMethodsWithNullValues() throws { @@ -622,6 +626,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "Credit Card") XCTAssertEqual(paymentMethod.fundingSource!, .credit) XCTAssertEqual(paymentMethod.brands, [.masterCard, .visa, .americanExpress]) + testCoding(paymentMethod) } func testDecodingDebitCardPaymentMethod() throws { @@ -630,6 +635,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "Credit Card") XCTAssertEqual(paymentMethod.fundingSource!, .debit) XCTAssertEqual(paymentMethod.brands, [.masterCard, .visa, .americanExpress]) + testCoding(paymentMethod) } func testDecodingBCMCCardPaymentMethod() throws { @@ -637,6 +643,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.type.rawValue, "bcmc") XCTAssertEqual(paymentMethod.name, "Bancontact card") XCTAssertEqual(paymentMethod.brands, []) + testCoding(paymentMethod) } func testDecodingCardPaymentMethodWithoutBrands() throws { @@ -647,6 +654,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.type.rawValue, "scheme") XCTAssertEqual(paymentMethod.name, "Credit Card") XCTAssertTrue(paymentMethod.brands.isEmpty) + testCoding(paymentMethod) } func testDecodingStoredCreditCardPaymentMethod() throws { @@ -663,6 +671,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.supportedShopperInteractions, [.shopperPresent, .shopperNotPresent]) XCTAssertEqual(paymentMethod.displayInformation(using: nil), expectedStoredCardPaymentMethodDisplayInfo(method: paymentMethod, localizationParameters: nil)) XCTAssertEqual(paymentMethod.displayInformation(using: expectedLocalizationParameters), expectedStoredCardPaymentMethodDisplayInfo(method: paymentMethod, localizationParameters: expectedLocalizationParameters)) + testCoding(paymentMethod) } func testDecodingStoredDebitCardPaymentMethod() throws { @@ -679,6 +688,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.supportedShopperInteractions, [.shopperPresent, .shopperNotPresent]) XCTAssertEqual(paymentMethod.displayInformation(using: nil), expectedStoredCardPaymentMethodDisplayInfo(method: paymentMethod, localizationParameters: nil)) XCTAssertEqual(paymentMethod.displayInformation(using: expectedLocalizationParameters), expectedStoredCardPaymentMethodDisplayInfo(method: paymentMethod, localizationParameters: expectedLocalizationParameters)) + testCoding(paymentMethod) } public func expectedStoredCardPaymentMethodDisplayInfo(method: StoredCardPaymentMethod, localizationParameters: LocalizationParameters?) -> DisplayInformation { @@ -713,6 +723,8 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.issuers[1].name, "Test Issuer 2") XCTAssertEqual(paymentMethod.issuers[2].identifier, "xxxx") XCTAssertEqual(paymentMethod.issuers[2].name, "Test Issuer 3") + + testCoding(paymentMethod) } func testDecodingIssuerListPaymentMethodWithoutDetailsObject() throws { @@ -727,6 +739,8 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.issuers[1].name, "Test Issuer 2") XCTAssertEqual(paymentMethod.issuers[2].identifier, "1153") XCTAssertEqual(paymentMethod.issuers[2].name, "Test Issuer 3") + + testCoding(paymentMethod) } // MARK: - SEPA Direct Debit @@ -740,6 +754,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(sepaDirectDebitDictionary) as SEPADirectDebitPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "sepadirectdebit") XCTAssertEqual(paymentMethod.name, "SEPA Direct Debit") + testCoding(paymentMethod) } // MARK: - Stored PayPal @@ -751,6 +766,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "PayPal") XCTAssertEqual(paymentMethod.emailAddress, "example@shopper.com") XCTAssertEqual(paymentMethod.supportedShopperInteractions, [.shopperPresent, .shopperNotPresent]) + testCoding(paymentMethod) } // MARK: - Apple Pay @@ -759,6 +775,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(applePayDictionary) as ApplePayPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "applepay") XCTAssertEqual(paymentMethod.name, "Apple Pay") + testCoding(paymentMethod) } // MARK: - Bancontact @@ -767,6 +784,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(bcmcCardDictionary) as BCMCPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "bcmc") XCTAssertEqual(paymentMethod.name, "Bancontact card") + testCoding(paymentMethod) } // MARK: - GiroPay @@ -775,6 +793,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(giroPayDictionaryWithOptionalDetails) as InstantPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "giropay") XCTAssertEqual(paymentMethod.name, "GiroPay") + testCoding(paymentMethod) } // MARK: - Seven Eleven @@ -783,6 +802,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(sevenElevenDictionary) as SevenElevenPaymentMethod XCTAssertEqual(paymentMethod.name, "7-Eleven") XCTAssertEqual(paymentMethod.type.rawValue, "econtext_seven_eleven") + testCoding(paymentMethod) } // MARK: - E-Context Online @@ -791,6 +811,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(econtextOnline) as EContextPaymentMethod XCTAssertEqual(paymentMethod.name, "Online Banking") XCTAssertEqual(paymentMethod.type.rawValue, "econtext_online") + testCoding(paymentMethod) } // MARK: - OXXO @@ -799,6 +820,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(oxxo) as OXXOPaymentMethod XCTAssertEqual(paymentMethod.name, "OXXO") XCTAssertEqual(paymentMethod.type.rawValue, "oxxo") + testCoding(paymentMethod) } // MARK: - E-Context ATM @@ -807,6 +829,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(econtextATM) as EContextPaymentMethod XCTAssertEqual(paymentMethod.name, "Pay-easy ATM") XCTAssertEqual(paymentMethod.type.rawValue, "econtext_atm") + testCoding(paymentMethod) } // MARK: - E-Context Stores @@ -815,6 +838,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(econtextStores) as EContextPaymentMethod XCTAssertEqual(paymentMethod.name, "Convenience Stores") XCTAssertEqual(paymentMethod.type.rawValue, "econtext_stores") + testCoding(paymentMethod) } // MARK: - Stored Bancontact @@ -835,6 +859,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.displayInformation(using: nil), expectedDisplayInfo) XCTAssertEqual(paymentMethod.displayInformation(using: expectedLocalizationParameters), expectedBancontactCardDisplayInfo(method: paymentMethod, localizationParameters: expectedLocalizationParameters)) + testCoding(paymentMethod) } // MARK: - MBWay @@ -843,6 +868,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(mbway) as MBWayPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "mbway") XCTAssertEqual(paymentMethod.name, "MB WAY") + testCoding(paymentMethod) } // MARK: - Doku wallet @@ -851,6 +877,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(dokuWallet) as DokuPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "doku_wallet") XCTAssertEqual(paymentMethod.name, "DOKU wallet") + testCoding(paymentMethod) } public func expectedBancontactCardDisplayInfo(method: StoredBCMCPaymentMethod, @@ -880,6 +907,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "Generic GiftCard") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "genericgiftcard") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "genericgiftcard") + testCoding(paymentMethod) } func testDecodingMealVoucherPaymentMethod() throws { @@ -888,6 +916,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "Sodexo") XCTAssertEqual(paymentMethod.displayInformation(using: nil).title, "Sodexo") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "mealVoucher_FR_sodexo") + testCoding(paymentMethod) } // MARK: - Boleto @@ -898,6 +927,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.name, "Boleto Bancario") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "boletobancario_santander") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "boletobancario_santander") + testCoding(paymentMethod) } // MARK: - BACS Direct Debit @@ -906,6 +936,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(bacsDirectDebit) as BACSDirectDebitPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "directdebit_GB") XCTAssertEqual(paymentMethod.name, "BACS Direct Debit") + testCoding(paymentMethod) } // MARK: - ACH Direct Debit @@ -914,6 +945,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(achDirectDebit) as ACHDirectDebitPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "ach") XCTAssertEqual(paymentMethod.name, "ACH Direct Debit") + testCoding(paymentMethod) } func testDecodingStoredACHDirectDebitPaymentMethod() throws { @@ -921,6 +953,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethod.type.rawValue, "ach") XCTAssertEqual(paymentMethod.name, "ACH Direct Debit") XCTAssertEqual(paymentMethod.bankAccountNumber, "123456789") + testCoding(paymentMethod) } // MARK: - Accessibility @@ -938,3 +971,23 @@ class PaymentMethodTests: XCTestCase { } } } + +private extension PaymentMethodTests { + + func testCoding(_ paymentMethod: T) { + do { + let encoded: Data = try AdyenCoder.encode(paymentMethod) + let decoded: T = try AdyenCoder.decode(encoded) + + // Re-Encode to compare if the data is still the same after the roundtrip + let reEncoded: Data = try AdyenCoder.encode(decoded) + + XCTAssertEqual( + String(data: encoded, encoding: .utf8), + String(data: reEncoded, encoding: .utf8) + ) + } catch { + XCTFail(error.localizedDescription) + } + } +} From 2c12be9ccdd57a5c272f03a2389d7183cc216940 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 4 Dec 2023 13:03:24 +0100 Subject: [PATCH 4/7] Added more tests --- .../Adyen Tests/Core/PaymentMethodTests.swift | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Tests/Adyen Tests/Core/PaymentMethodTests.swift b/Tests/Adyen Tests/Core/PaymentMethodTests.swift index 7fd9d08526..324a56443c 100644 --- a/Tests/Adyen Tests/Core/PaymentMethodTests.swift +++ b/Tests/Adyen Tests/Core/PaymentMethodTests.swift @@ -905,7 +905,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(giftCard) as GiftCardPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "giftcard") XCTAssertEqual(paymentMethod.name, "Generic GiftCard") - XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "genericgiftcard") + XCTAssertEqual(paymentMethod.displayInformation(using: nil).title, "Generic GiftCard") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "genericgiftcard") testCoding(paymentMethod) } @@ -925,7 +925,7 @@ class PaymentMethodTests: XCTestCase { let paymentMethod = try AdyenCoder.decode(boleto) as BoletoPaymentMethod XCTAssertEqual(paymentMethod.type.rawValue, "boletobancario_santander") XCTAssertEqual(paymentMethod.name, "Boleto Bancario") - XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "boletobancario_santander") + XCTAssertEqual(paymentMethod.displayInformation(using: nil).title, "Boleto Bancario") XCTAssertEqual(paymentMethod.displayInformation(using: nil).logoName, "boletobancario_santander") testCoding(paymentMethod) } @@ -956,6 +956,24 @@ class PaymentMethodTests: XCTestCase { testCoding(paymentMethod) } + // MARK: - Cash App + + func testDecodingCashAppPayPaymentMethod() throws { + let paymentMethod = try AdyenCoder.decode(cashAppPay) as CashAppPayPaymentMethod + XCTAssertEqual(paymentMethod.type.rawValue, "cashapp") + XCTAssertEqual(paymentMethod.name, "Cash App Pay") + testCoding(paymentMethod) + } + + // MARK: - Cash App + + func testDecodingQiwiPaymentMethod() throws { + let paymentMethod = try AdyenCoder.decode(qiwiWallet) as QiwiWalletPaymentMethod + XCTAssertEqual(paymentMethod.type.rawValue, "qiwiwallet") + XCTAssertEqual(paymentMethod.name, "Qiwi Wallet") + testCoding(paymentMethod) + } + // MARK: - Accessibility func testPaymentMethodTypeName() throws { From 82d568f932099b42b71b704995a07e294a822858 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 4 Dec 2023 15:42:39 +0100 Subject: [PATCH 5/7] Reverted renaming of Decoder to Interpreter --- .../Abstract/AnyPaymentMethod.swift | 4 +- .../Abstract/AnyPaymentMethodDecoder.swift | 172 +++++++++--------- 2 files changed, 86 insertions(+), 90 deletions(-) diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift index d6c6759fab..73add95e16 100644 --- a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethod.swift @@ -82,7 +82,7 @@ internal enum AnyPaymentMethod: Codable { // MARK: - Decoding internal init(from decoder: Decoder) throws { - self = AnyPaymentMethodInterpreter.decode(from: decoder) + self = AnyPaymentMethodDecoder.decode(from: decoder) } internal func encode(to encoder: Encoder) throws { @@ -100,7 +100,7 @@ internal enum AnyPaymentMethod: Codable { extension AnyPaymentMethod { init(_ paymentMethod: PaymentMethod) { - self = AnyPaymentMethodInterpreter.anyPaymentMethod(from: paymentMethod) + self = AnyPaymentMethodDecoder.anyPaymentMethod(from: paymentMethod) } } diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift index 45a3a14d47..0062792aee 100644 --- a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift @@ -30,64 +30,63 @@ private struct PaymentMethodField: Decodable { } -internal enum AnyPaymentMethodInterpreter { - - private static var interpreters: [PaymentMethodType: PaymentMethodInterpreter] = [ +internal enum AnyPaymentMethodDecoder { + private static var decoders: [PaymentMethodType: PaymentMethodDecoder] = [ // Unsupported payment methods - .bcmcMobileQR: UnsupportedPaymentMethodInterpreter(), - .weChatMiniProgram: UnsupportedPaymentMethodInterpreter(), - .weChatQR: UnsupportedPaymentMethodInterpreter(), - .weChatPayWeb: UnsupportedPaymentMethodInterpreter(), - .googlePay: UnsupportedPaymentMethodInterpreter(), - .afterpay: UnsupportedPaymentMethodInterpreter(), - .androidPay: UnsupportedPaymentMethodInterpreter(), - .amazonPay: UnsupportedPaymentMethodInterpreter(), - .bizum: UnsupportedPaymentMethodInterpreter(), + .bcmcMobileQR: UnsupportedPaymentMethodDecoder(), + .weChatMiniProgram: UnsupportedPaymentMethodDecoder(), + .weChatQR: UnsupportedPaymentMethodDecoder(), + .weChatPayWeb: UnsupportedPaymentMethodDecoder(), + .googlePay: UnsupportedPaymentMethodDecoder(), + .afterpay: UnsupportedPaymentMethodDecoder(), + .androidPay: UnsupportedPaymentMethodDecoder(), + .amazonPay: UnsupportedPaymentMethodDecoder(), + .bizum: UnsupportedPaymentMethodDecoder(), // Supported payment methods - .card: CardPaymentMethodInterpreter(), - .scheme: CardPaymentMethodInterpreter(), - .ideal: IssuerListPaymentMethodInterpreter(), - .entercash: IssuerListPaymentMethodInterpreter(), - .eps: IssuerListPaymentMethodInterpreter(), - .dotpay: IssuerListPaymentMethodInterpreter(), - .onlineBankingPoland: IssuerListPaymentMethodInterpreter(), - .openBankingUK: IssuerListPaymentMethodInterpreter(), - .molPayEBankingFPXMY: IssuerListPaymentMethodInterpreter(), - .molPayEBankingTH: IssuerListPaymentMethodInterpreter(), - .molPayEBankingVN: IssuerListPaymentMethodInterpreter(), - .sepaDirectDebit: SEPADirectDebitPaymentMethodInterpreter(), - .bacsDirectDebit: BACSDirectDebitPaymentMethodInterpreter(), - .achDirectDebit: ACHDirectDebitPaymentMethodInterpreter(), - .applePay: ApplePayPaymentMethodInterpreter(), - .payPal: PayPalPaymentMethodInterpreter(), - .bcmc: BCMCCardPaymentMethodInterpreter(), - .weChatPaySDK: WeChatPayPaymentMethodInterpreter(), - .qiwiWallet: QiwiWalletPaymentMethodInterpreter(), - .mbWay: MBWayPaymentMethodInterpreter(), - .blik: BLIKPaymentMethodInterpreter(), - .dokuWallet: DokuPaymentMethodInterpreter(), - .dokuAlfamart: DokuPaymentMethodInterpreter(), - .dokuIndomaret: DokuPaymentMethodInterpreter(), - .giftcard: GiftCardPaymentMethodInterpreter(), - .mealVoucherSodexo: MealVoucherPaymentMethodInterpreter(), - .mealVoucherNatixis: MealVoucherPaymentMethodInterpreter(), - .mealVoucherGroupeUp: MealVoucherPaymentMethodInterpreter(), - .econtextSevenEleven: SevenElevenPaymentMethodInterpreter(), - .econtextStores: EContextStoresPaymentMethodInterpreter(), - .econtextATM: EContextATMPaymentMethodInterpreter(), - .econtextOnline: EContextOnlinePaymentMethodInterpreter(), - .boleto: BoletoPaymentMethodInterpreter(), - .affirm: AffirmPaymentMethodInterpreter(), - .atome: AtomePaymentMethodInterpreter(), - .onlineBankingCZ: OnlineBankingPaymentMethodInterpreter(), - .onlineBankingSK: OnlineBankingPaymentMethodInterpreter(), - .upi: UPIPaymentMethodInterpreter(), - .cashAppPay: CashAppPayPaymentMethodInterpreter() + .card: CardPaymentMethodDecoder(), + .scheme: CardPaymentMethodDecoder(), + .ideal: IssuerListPaymentMethodDecoder(), + .entercash: IssuerListPaymentMethodDecoder(), + .eps: IssuerListPaymentMethodDecoder(), + .dotpay: IssuerListPaymentMethodDecoder(), + .onlineBankingPoland: IssuerListPaymentMethodDecoder(), + .openBankingUK: IssuerListPaymentMethodDecoder(), + .molPayEBankingFPXMY: IssuerListPaymentMethodDecoder(), + .molPayEBankingTH: IssuerListPaymentMethodDecoder(), + .molPayEBankingVN: IssuerListPaymentMethodDecoder(), + .sepaDirectDebit: SEPADirectDebitPaymentMethodDecoder(), + .bacsDirectDebit: BACSDirectDebitPaymentMethodDecoder(), + .achDirectDebit: ACHDirectDebitPaymentMethodDecoder(), + .applePay: ApplePayPaymentMethodDecoder(), + .payPal: PayPalPaymentMethodDecoder(), + .bcmc: BCMCCardPaymentMethodDecoder(), + .weChatPaySDK: WeChatPayPaymentMethodDecoder(), + .qiwiWallet: QiwiWalletPaymentMethodDecoder(), + .mbWay: MBWayPaymentMethodDecoder(), + .blik: BLIKPaymentMethodDecoder(), + .dokuWallet: DokuPaymentMethodDecoder(), + .dokuAlfamart: DokuPaymentMethodDecoder(), + .dokuIndomaret: DokuPaymentMethodDecoder(), + .giftcard: GiftCardPaymentMethodDecoder(), + .mealVoucherSodexo: MealVoucherPaymentMethodDecoder(), + .mealVoucherNatixis: MealVoucherPaymentMethodDecoder(), + .mealVoucherGroupeUp: MealVoucherPaymentMethodDecoder(), + .econtextSevenEleven: SevenElevenPaymentMethodDecoder(), + .econtextStores: EContextStoresPaymentMethodDecoder(), + .econtextATM: EContextATMPaymentMethodDecoder(), + .econtextOnline: EContextOnlinePaymentMethodDecoder(), + .boleto: BoletoPaymentMethodDecoder(), + .affirm: AffirmPaymentMethodDecoder(), + .atome: AtomePaymentMethodDecoder(), + .onlineBankingCZ: OnlineBankingPaymentMethodDecoder(), + .onlineBankingSK: OnlineBankingPaymentMethodDecoder(), + .upi: UPIPaymentMethodDecoder(), + .cashAppPay: CashAppPayPaymentMethodDecoder() ] - private static var defaultInterpreter: PaymentMethodInterpreter = InstantPaymentMethodInterpreter() + private static var defaultDecoder: PaymentMethodDecoder = InstantPaymentMethodDecoder() internal static func decode(from decoder: Decoder) -> AnyPaymentMethod { do { @@ -99,9 +98,9 @@ internal enum AnyPaymentMethodInterpreter { if isIssuersList { if type == "onlineBanking_CZ" || type == "onlineBanking_SK" { - return try OnlineBankingPaymentMethodInterpreter().decode(from: decoder, isStored: isStored) + return try OnlineBankingPaymentMethodDecoder().decode(from: decoder, isStored: isStored) } - return try IssuerListPaymentMethodInterpreter().decode(from: decoder, isStored: isStored) + return try IssuerListPaymentMethodDecoder().decode(from: decoder, isStored: isStored) } // This is a hack to handle stored Bancontact as a separate @@ -113,13 +112,10 @@ internal enum AnyPaymentMethodInterpreter { // This matching struct will be used as the key to the decoders // dictionary. if isStored, brand == "bcmc", type == "scheme" { - return try interpreters[.bcmc, default: defaultInterpreter].decode(from: decoder, isStored: true) + return try decoders[.bcmc, default: defaultDecoder].decode(from: decoder, isStored: true) } - let paymentDecoder = PaymentMethodType(rawValue: type).map { - interpreters[$0, default: defaultInterpreter] - } ?? defaultInterpreter - + let paymentDecoder = PaymentMethodType(rawValue: type).map { decoders[$0, default: defaultDecoder] } ?? defaultDecoder return try paymentDecoder.decode(from: decoder, isStored: isStored) } catch { return .none @@ -127,17 +123,17 @@ internal enum AnyPaymentMethodInterpreter { } internal static func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod { - let paymentDecoder = interpreters[paymentMethod.type] ?? defaultInterpreter + let paymentDecoder = decoders[paymentMethod.type] ?? defaultDecoder return paymentDecoder.anyPaymentMethod(from: paymentMethod) ?? .instant(paymentMethod) } } -private protocol PaymentMethodInterpreter { +private protocol PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? } -private struct CardPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct CardPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedCard(StoredCardPaymentMethod(from: decoder)) @@ -157,7 +153,7 @@ private struct CardPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct BCMCCardPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct BCMCCardPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedBCMC(StoredBCMCPaymentMethod(from: decoder)) @@ -177,7 +173,7 @@ private struct BCMCCardPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct IssuerListPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct IssuerListPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .issuerList(IssuerListPaymentMethod(from: decoder)) } @@ -187,7 +183,7 @@ private struct IssuerListPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct SEPADirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct SEPADirectDebitPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .sepaDirectDebit(SEPADirectDebitPaymentMethod(from: decoder)) } @@ -197,7 +193,7 @@ private struct SEPADirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter } } -private struct BACSDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct BACSDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .bacsDirectDebit(BACSDirectDebitPaymentMethod(from: decoder)) } @@ -207,7 +203,7 @@ private struct BACSDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter } } -private struct ACHDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct ACHDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedAchDirectDebit(StoredACHDirectDebitPaymentMethod(from: decoder)) @@ -227,7 +223,7 @@ private struct ACHDirectDebitPaymentMethodInterpreter: PaymentMethodInterpreter } } -private struct ApplePayPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct ApplePayPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .applePay(ApplePayPaymentMethod(from: decoder)) } @@ -237,7 +233,7 @@ private struct ApplePayPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct PayPalPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct PayPalPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedPayPal(StoredPayPalPaymentMethod(from: decoder)) @@ -257,7 +253,7 @@ private struct PayPalPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct InstantPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct InstantPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedInstant(StoredInstantPaymentMethod(from: decoder)) @@ -277,7 +273,7 @@ private struct InstantPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct WeChatPayPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct WeChatPayPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .weChatPay(WeChatPayPaymentMethod(from: decoder)) } @@ -287,7 +283,7 @@ private struct WeChatPayPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct UnsupportedPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct UnsupportedPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { .none } @@ -297,7 +293,7 @@ private struct UnsupportedPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct QiwiWalletPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct QiwiWalletPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .qiwiWallet(QiwiWalletPaymentMethod(from: decoder)) } @@ -307,7 +303,7 @@ private struct QiwiWalletPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct MBWayPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct MBWayPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .mbWay(MBWayPaymentMethod(from: decoder)) } @@ -317,7 +313,7 @@ private struct MBWayPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct BLIKPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct BLIKPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { if isStored { return try .storedBlik(StoredBLIKPaymentMethod(from: decoder)) @@ -337,7 +333,7 @@ private struct BLIKPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct DokuPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct DokuPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .doku(DokuPaymentMethod(from: decoder)) } @@ -347,7 +343,7 @@ private struct DokuPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct GiftCardPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct GiftCardPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .giftcard(GiftCardPaymentMethod(from: decoder)) } @@ -357,7 +353,7 @@ private struct GiftCardPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct MealVoucherPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct MealVoucherPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .mealVoucher(MealVoucherPaymentMethod(from: decoder)) } @@ -367,7 +363,7 @@ private struct MealVoucherPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct SevenElevenPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct SevenElevenPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .sevenEleven(SevenElevenPaymentMethod(from: decoder)) } @@ -377,7 +373,7 @@ private struct SevenElevenPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct EContextStoresPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct EContextStoresPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextStores(EContextPaymentMethod(from: decoder)) } @@ -387,7 +383,7 @@ private struct EContextStoresPaymentMethodInterpreter: PaymentMethodInterpreter } } -private struct EContextATMPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct EContextATMPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextATM(EContextPaymentMethod(from: decoder)) } @@ -397,7 +393,7 @@ private struct EContextATMPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct EContextOnlinePaymentMethodInterpreter: PaymentMethodInterpreter { +private struct EContextOnlinePaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .econtextOnline(EContextPaymentMethod(from: decoder)) } @@ -407,7 +403,7 @@ private struct EContextOnlinePaymentMethodInterpreter: PaymentMethodInterpreter } } -private struct BoletoPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct BoletoPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .boleto(BoletoPaymentMethod(from: decoder)) } @@ -417,7 +413,7 @@ private struct BoletoPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct AffirmPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct AffirmPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .affirm(AffirmPaymentMethod(from: decoder)) } @@ -427,7 +423,7 @@ private struct AffirmPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct AtomePaymentMethodInterpreter: PaymentMethodInterpreter { +private struct AtomePaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .atome(AtomePaymentMethod(from: decoder)) } @@ -437,7 +433,7 @@ private struct AtomePaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct OnlineBankingPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct OnlineBankingPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .onlineBanking(OnlineBankingPaymentMethod(from: decoder)) } @@ -447,7 +443,7 @@ private struct OnlineBankingPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct UPIPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct UPIPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { try .upi(UPIPaymentMethod(from: decoder)) } @@ -457,7 +453,7 @@ private struct UPIPaymentMethodInterpreter: PaymentMethodInterpreter { } } -private struct CashAppPayPaymentMethodInterpreter: PaymentMethodInterpreter { +private struct CashAppPayPaymentMethodDecoder: PaymentMethodDecoder { func decode(from decoder: Decoder, isStored: Bool) throws -> AnyPaymentMethod { #if canImport(PayKit) if isStored { From 708011a7ce09bcc38cf1a3c2a66ff586e108e90f Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Tue, 5 Dec 2023 11:40:49 +0100 Subject: [PATCH 6/7] Adding any + more tests --- .../Abstract/AnyPaymentMethodDecoder.swift | 54 +++++++++---------- .../Adyen Tests/Core/PaymentMethodTests.swift | 44 +++++++++++---- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift index 0062792aee..6a7301248e 100644 --- a/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift +++ b/Adyen/Core/Payment Methods/Abstract/AnyPaymentMethodDecoder.swift @@ -142,7 +142,7 @@ private struct CardPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredCardPaymentMethod { return .storedCard(method) } @@ -162,7 +162,7 @@ private struct BCMCCardPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredBCMCPaymentMethod { return .storedBCMC(method) } @@ -178,7 +178,7 @@ private struct IssuerListPaymentMethodDecoder: PaymentMethodDecoder { try .issuerList(IssuerListPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? IssuerListPaymentMethod).map { .issuerList($0) } } } @@ -188,7 +188,7 @@ private struct SEPADirectDebitPaymentMethodDecoder: PaymentMethodDecoder { try .sepaDirectDebit(SEPADirectDebitPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? SEPADirectDebitPaymentMethod).map { .sepaDirectDebit($0) } } } @@ -198,7 +198,7 @@ private struct BACSDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { try .bacsDirectDebit(BACSDirectDebitPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? BACSDirectDebitPaymentMethod).map { .bacsDirectDebit($0) } } } @@ -212,7 +212,7 @@ private struct ACHDirectDebitPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredACHDirectDebitPaymentMethod { return .storedAchDirectDebit(method) } @@ -228,7 +228,7 @@ private struct ApplePayPaymentMethodDecoder: PaymentMethodDecoder { try .applePay(ApplePayPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? ApplePayPaymentMethod).map { .applePay($0) } } } @@ -242,7 +242,7 @@ private struct PayPalPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredPayPalPaymentMethod { return .storedPayPal(method) } @@ -262,7 +262,7 @@ private struct InstantPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredInstantPaymentMethod { return .storedInstant(method) } @@ -278,7 +278,7 @@ private struct WeChatPayPaymentMethodDecoder: PaymentMethodDecoder { try .weChatPay(WeChatPayPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? WeChatPayPaymentMethod).map { .weChatPay($0) } } } @@ -288,7 +288,7 @@ private struct UnsupportedPaymentMethodDecoder: PaymentMethodDecoder { .none } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { nil } } @@ -298,7 +298,7 @@ private struct QiwiWalletPaymentMethodDecoder: PaymentMethodDecoder { try .qiwiWallet(QiwiWalletPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? QiwiWalletPaymentMethod).map { .qiwiWallet($0) } } } @@ -308,7 +308,7 @@ private struct MBWayPaymentMethodDecoder: PaymentMethodDecoder { try .mbWay(MBWayPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? MBWayPaymentMethod).map { .mbWay($0) } } } @@ -322,7 +322,7 @@ private struct BLIKPaymentMethodDecoder: PaymentMethodDecoder { } } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { if let method = paymentMethod as? StoredBLIKPaymentMethod { return .storedBlik(method) } @@ -338,7 +338,7 @@ private struct DokuPaymentMethodDecoder: PaymentMethodDecoder { try .doku(DokuPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? DokuPaymentMethod).map { .doku($0) } } } @@ -348,7 +348,7 @@ private struct GiftCardPaymentMethodDecoder: PaymentMethodDecoder { try .giftcard(GiftCardPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? GiftCardPaymentMethod).map { .giftcard($0) } } } @@ -358,7 +358,7 @@ private struct MealVoucherPaymentMethodDecoder: PaymentMethodDecoder { try .mealVoucher(MealVoucherPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? MealVoucherPaymentMethod).map { .mealVoucher($0) } } } @@ -368,7 +368,7 @@ private struct SevenElevenPaymentMethodDecoder: PaymentMethodDecoder { try .sevenEleven(SevenElevenPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? SevenElevenPaymentMethod).map { .sevenEleven($0) } } } @@ -378,7 +378,7 @@ private struct EContextStoresPaymentMethodDecoder: PaymentMethodDecoder { try .econtextStores(EContextPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextStores($0) } } } @@ -388,7 +388,7 @@ private struct EContextATMPaymentMethodDecoder: PaymentMethodDecoder { try .econtextATM(EContextPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextATM($0) } } } @@ -398,7 +398,7 @@ private struct EContextOnlinePaymentMethodDecoder: PaymentMethodDecoder { try .econtextOnline(EContextPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? EContextPaymentMethod).map { .econtextOnline($0) } } } @@ -408,7 +408,7 @@ private struct BoletoPaymentMethodDecoder: PaymentMethodDecoder { try .boleto(BoletoPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? BoletoPaymentMethod).map { .boleto($0) } } } @@ -418,7 +418,7 @@ private struct AffirmPaymentMethodDecoder: PaymentMethodDecoder { try .affirm(AffirmPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? AffirmPaymentMethod).map { .affirm($0) } } } @@ -428,7 +428,7 @@ private struct AtomePaymentMethodDecoder: PaymentMethodDecoder { try .atome(AtomePaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? AtomePaymentMethod).map { .atome($0) } } } @@ -438,7 +438,7 @@ private struct OnlineBankingPaymentMethodDecoder: PaymentMethodDecoder { try .onlineBanking(OnlineBankingPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? OnlineBankingPaymentMethod).map { .onlineBanking($0) } } } @@ -448,7 +448,7 @@ private struct UPIPaymentMethodDecoder: PaymentMethodDecoder { try .upi(UPIPaymentMethod(from: decoder)) } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { (paymentMethod as? UPIPaymentMethod).map { .upi($0) } } } @@ -466,7 +466,7 @@ private struct CashAppPayPaymentMethodDecoder: PaymentMethodDecoder { #endif } - func anyPaymentMethod(from paymentMethod: PaymentMethod) -> AnyPaymentMethod? { + func anyPaymentMethod(from paymentMethod: any PaymentMethod) -> AnyPaymentMethod? { #if canImport(PayKit) if let method = paymentMethod as? StoredCashAppPayPaymentMethod { return .storedCashAppPay(method) diff --git a/Tests/Adyen Tests/Core/PaymentMethodTests.swift b/Tests/Adyen Tests/Core/PaymentMethodTests.swift index 324a56443c..8ac885054f 100644 --- a/Tests/Adyen Tests/Core/PaymentMethodTests.swift +++ b/Tests/Adyen Tests/Core/PaymentMethodTests.swift @@ -69,7 +69,12 @@ class PaymentMethodTests: XCTestCase { giftCard1, givexGiftCard, mealVoucherSodexo, - bizum + bizum, + boleto, + affirm, + atome, + upi, + cashAppPay ] ] } @@ -159,9 +164,10 @@ class PaymentMethodTests: XCTestCase { // Regular payment methods - XCTAssertEqual(paymentMethods.regular.count, 26) - XCTAssertTrue(paymentMethods.regular[0] is CardPaymentMethod) - XCTAssertEqual((paymentMethods.regular[0] as! CardPaymentMethod).fundingSource!, .credit) + XCTAssertEqual(paymentMethods.regular.count, 31) + + let creditCardPaymentMethod = try XCTUnwrap(paymentMethods.regular[0] as? CardPaymentMethod) + XCTAssertEqual(creditCardPaymentMethod.fundingSource, .credit) XCTAssertTrue(paymentMethods.regular[1] is IssuerListPaymentMethod) XCTAssertTrue(paymentMethods.regular[2] is SEPADirectDebitPaymentMethod) @@ -197,8 +203,7 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethods.regular[8].name, "GiroPay with non optional details") // Qiwi Wallet - XCTAssertTrue(paymentMethods.regular[9] is QiwiWalletPaymentMethod) - let qiwiMethod = paymentMethods.regular[9] as! QiwiWalletPaymentMethod + let qiwiMethod = try XCTUnwrap(paymentMethods.regular[9] as? QiwiWalletPaymentMethod) XCTAssertEqual(qiwiMethod.type.rawValue, "qiwiwallet") XCTAssertEqual(qiwiMethod.name, "Qiwi Wallet") XCTAssertEqual(qiwiMethod.phoneExtensions.count, 3) @@ -215,8 +220,8 @@ class PaymentMethodTests: XCTestCase { XCTAssertEqual(paymentMethods.regular[10].type.rawValue, "wechatpaySDK") XCTAssertEqual(paymentMethods.regular[10].name, "WeChat Pay") - XCTAssertTrue(paymentMethods.regular[11] is CardPaymentMethod) - XCTAssertEqual((paymentMethods.regular[11] as! CardPaymentMethod).fundingSource!, .debit) + let debitCardPaymentMethod = try XCTUnwrap(paymentMethods.regular[11] as? CardPaymentMethod) + XCTAssertEqual(debitCardPaymentMethod.fundingSource, .debit) XCTAssertTrue(paymentMethods.regular[12] is MBWayPaymentMethod) XCTAssertEqual(paymentMethods.regular[12].name, "MB WAY") @@ -273,7 +278,28 @@ class PaymentMethodTests: XCTestCase { XCTAssertTrue(paymentMethods.regular[25] is MealVoucherPaymentMethod) XCTAssertEqual(paymentMethods.regular[25].name, "Sodexo") XCTAssertEqual(paymentMethods.regular[25].type.rawValue, "mealVoucher_FR_sodexo") - + + XCTAssertTrue(paymentMethods.regular[26] is BoletoPaymentMethod) + XCTAssertEqual(paymentMethods.regular[26].name, "Boleto Bancario") + XCTAssertEqual(paymentMethods.regular[26].type.rawValue, "boletobancario_santander") + + XCTAssertTrue(paymentMethods.regular[27] is AffirmPaymentMethod) + XCTAssertEqual(paymentMethods.regular[27].name, "Affirm") + XCTAssertEqual(paymentMethods.regular[27].type.rawValue, "affirm") + + XCTAssertTrue(paymentMethods.regular[28] is AtomePaymentMethod) + XCTAssertEqual(paymentMethods.regular[28].name, "Atome") + XCTAssertEqual(paymentMethods.regular[28].type.rawValue, "atome") + + XCTAssertTrue(paymentMethods.regular[29] is UPIPaymentMethod) + XCTAssertEqual(paymentMethods.regular[29].name, "UPI") + XCTAssertEqual(paymentMethods.regular[29].type.rawValue, "upi") + + let cashAppPay = try XCTUnwrap(paymentMethods.regular[30] as? CashAppPayPaymentMethod) + XCTAssertEqual(cashAppPay.name, "Cash App Pay") + XCTAssertEqual(cashAppPay.type.rawValue, "cashapp") + XCTAssertEqual(cashAppPay.clientId, "testClient") + XCTAssertEqual(cashAppPay.scopeId, "testScope") } // MARK: - Display Information Override From f1219c41458c7a460cb13242c239b05adfe78261 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Tue, 5 Dec 2023 15:53:28 +0100 Subject: [PATCH 7/7] Fixing tests --- Tests/DropIn Tests/ComponentManagerTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/DropIn Tests/ComponentManagerTests.swift b/Tests/DropIn Tests/ComponentManagerTests.swift index d9ae323c2c..b81d359240 100644 --- a/Tests/DropIn Tests/ComponentManagerTests.swift +++ b/Tests/DropIn Tests/ComponentManagerTests.swift @@ -475,9 +475,11 @@ class ComponentManagerTests: XCTestCase { init() {} init(from decoder: Decoder) throws {} + + enum CodingKeys: CodingKey {} // Satisfying Encoding requirement } - var dummy = DummyPaymentMethod() + let dummy = DummyPaymentMethod() let expectation = expectation(description: "Access expectation") expectation.expectedFulfillmentCount = 1