From 8c421e73122337f0d63884033053ec8bd7fddbda Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 13:18:04 +1100 Subject: [PATCH 1/7] Delete currency locale --- Sources/Afterpay/Model/Currency.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Sources/Afterpay/Model/Currency.swift b/Sources/Afterpay/Model/Currency.swift index 433a71d9..1c1e2acf 100644 --- a/Sources/Afterpay/Model/Currency.swift +++ b/Sources/Afterpay/Model/Currency.swift @@ -27,19 +27,6 @@ struct Currency { } } - var locale: Locale { - switch code { - case Locales.australia.currencyCode: - return Locales.australia - case Locales.newZealand.currencyCode: - return Locales.newZealand - case Locales.canada.currencyCode: - return Locales.canada - default: - return Locales.unitedStates - } - } - init?(currencyCode: String) { let currencyName = Locales.posix.localizedString(forCurrencyCode: currencyCode) From 31d92691d94f0aa66076d0cd29afcdd347575769 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 13:40:20 +1100 Subject: [PATCH 2/7] Move to using CurrencyFormatter which takes a locale --- Afterpay.xcodeproj/project.pbxproj | 8 ++-- Sources/Afterpay/Model/Configuration.swift | 10 ++--- Sources/Afterpay/Model/Currency.swift | 40 ------------------- .../Afterpay/Model/CurrencyFormatter.swift | 25 ++++++++++++ Sources/Afterpay/Model/PriceBreakdown.swift | 16 ++------ 5 files changed, 38 insertions(+), 61 deletions(-) delete mode 100644 Sources/Afterpay/Model/Currency.swift create mode 100644 Sources/Afterpay/Model/CurrencyFormatter.swift diff --git a/Afterpay.xcodeproj/project.pbxproj b/Afterpay.xcodeproj/project.pbxproj index 836a963f..b5075b89 100644 --- a/Afterpay.xcodeproj/project.pbxproj +++ b/Afterpay.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 15F7DDB725393BD30011EC25 /* CurrencyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F7DDB625393BD30011EC25 /* CurrencyFormatter.swift */; }; 6602EF0F25358A8000A0468C /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6602EF0E25358A8000A0468C /* ColorScheme.swift */; }; 6605666324E5199500DA588E /* Locales.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6605666224E5199500DA588E /* Locales.swift */; }; 6615F99B24D14620005036F1 /* SVG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6615F99A24D14620005036F1 /* SVG.swift */; }; @@ -22,7 +23,6 @@ 667AD3542497121200BF94E5 /* CheckoutWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667AD3532497121100BF94E5 /* CheckoutWebViewController.swift */; }; 6689536C24C96CB5005090B4 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6689536B24C96CB5005090B4 /* Configuration.swift */; }; 66D685B224BD3FB900C7287C /* SwiftUIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D685B124BD3FB900C7287C /* SwiftUIWrapper.swift */; }; - 66DAAC8924E0CE7700127460 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DAAC8824E0CE7700127460 /* Currency.swift */; }; 66DAAC8B24E0CF0100127460 /* PriceBreakdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DAAC8A24E0CF0100127460 /* PriceBreakdown.swift */; }; 66DAAC8D24E109D200127460 /* PriceBreakdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DAAC8C24E109D200127460 /* PriceBreakdownTests.swift */; }; 66E255AE24E3C14600C81F20 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66E255AD24E3C14600C81F20 /* Strings.swift */; }; @@ -43,6 +43,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 15F7DDB625393BD30011EC25 /* CurrencyFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyFormatter.swift; sourceTree = ""; }; 6602EF0E25358A8000A0468C /* ColorScheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = ""; }; 6605666224E5199500DA588E /* Locales.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locales.swift; sourceTree = ""; }; 6615F99A24D14620005036F1 /* SVG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVG.swift; sourceTree = ""; }; @@ -71,7 +72,6 @@ 66B57E56248F5C7D0020C642 /* Project-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = ""; }; 66B57E57248F5C7D0020C642 /* Afterpay-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Afterpay-Release.xcconfig"; sourceTree = ""; }; 66D685B124BD3FB900C7287C /* SwiftUIWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIWrapper.swift; sourceTree = ""; }; - 66DAAC8824E0CE7700127460 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = ""; }; 66DAAC8A24E0CF0100127460 /* PriceBreakdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceBreakdown.swift; sourceTree = ""; }; 66DAAC8C24E109D200127460 /* PriceBreakdownTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceBreakdownTests.swift; sourceTree = ""; }; 66E255AD24E3C14600C81F20 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; @@ -209,7 +209,7 @@ isa = PBXGroup; children = ( 6689536B24C96CB5005090B4 /* Configuration.swift */, - 66DAAC8824E0CE7700127460 /* Currency.swift */, + 15F7DDB625393BD30011EC25 /* CurrencyFormatter.swift */, 6605666224E5199500DA588E /* Locales.swift */, 66DAAC8A24E0CF0100127460 /* PriceBreakdown.swift */, ); @@ -432,6 +432,7 @@ 6602EF0F25358A8000A0468C /* ColorScheme.swift in Sources */, 6672982A25357D80001D1C5A /* SVGConfiguration.swift in Sources */, 6689536C24C96CB5005090B4 /* Configuration.swift in Sources */, + 15F7DDB725393BD30011EC25 /* CurrencyFormatter.swift in Sources */, 66DAAC8B24E0CF0100127460 /* PriceBreakdown.swift in Sources */, 662A3AED24A999A500EFD826 /* CheckoutResult.swift in Sources */, 667AD3542497121200BF94E5 /* CheckoutWebViewController.swift in Sources */, @@ -440,7 +441,6 @@ 66D685B224BD3FB900C7287C /* SwiftUIWrapper.swift in Sources */, 666D334C24A48F5C00FCD464 /* ObjcWrapper.swift in Sources */, 946388FE24DD077F00A1227A /* InfoWebViewController.swift in Sources */, - 66DAAC8924E0CE7700127460 /* Currency.swift in Sources */, 66EE9BD724DCEC3E00A81C19 /* LinkTextView.swift in Sources */, 6605666324E5199500DA588E /* Locales.swift in Sources */, ); diff --git a/Sources/Afterpay/Model/Configuration.swift b/Sources/Afterpay/Model/Configuration.swift index 4b3322ef..a1df4fa1 100644 --- a/Sources/Afterpay/Model/Configuration.swift +++ b/Sources/Afterpay/Model/Configuration.swift @@ -39,7 +39,7 @@ public struct Configuration { let minimumAmount: Decimal? let maximumAmount: Decimal - let currency: Currency + let currencyCode: String let locale: Locale /// Creates a new configuration by taking in a minimum and maximum amount as well as a currency @@ -71,8 +71,8 @@ public struct Configuration { /// rounded to 2 decimal places. However values convertible to a Swift Decimal are accepted. /// - maximumAmount: A amount string representation of a decimal number, rounded to 2 /// decimal places. However values convertible to a Swift Decimal are accepted. - /// - currencyCode: The currency in ISO 4217 format. Supported values include "AUD", "NZD", - /// "USD", and "CAD". However values recognized by Foundation are accepted. + /// - currencyCode: The currency in ISO 4217 format. Supported values include "AUD", "CAD", + /// "GBP", "NZD" and "USD". /// - locale: The locale required for display of the appropriate terms and conditions and used /// for formatting of currency. For example if the locale is set to en_AU are specified as USD. /// More examples are available in the currency tab of the js sandbox: @@ -101,7 +101,7 @@ public struct Configuration { throw ConfigurationError.invalidOrdering(minimum: minimumAmount!, maximum: maximumAmount) } - guard let currency = Currency(currencyCode: currencyCode) else { + guard Locales.validSet.map(\.currencyCode).contains(currencyCode) else { throw ConfigurationError.invalidCurrencyCode(currencyCode) } @@ -111,7 +111,7 @@ public struct Configuration { self.minimumAmount = minimumDecimal self.maximumAmount = maximumDecimal - self.currency = currency + self.currencyCode = currencyCode self.locale = locale } diff --git a/Sources/Afterpay/Model/Currency.swift b/Sources/Afterpay/Model/Currency.swift deleted file mode 100644 index 1c1e2acf..00000000 --- a/Sources/Afterpay/Model/Currency.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Currency.swift -// Afterpay -// -// Created by Adam Campbell on 10/8/20. -// Copyright © 2020 Afterpay. All rights reserved. -// - -import Foundation - -private let unknownCurrencyName = "Unknown Currency" - -struct Currency { - - let code: String - - var symbol: String { - switch code { - case Locales.australia.currencyCode: - return "A$" - case Locales.newZealand.currencyCode: - return "NZ$" - case Locales.canada.currencyCode: - return "CA$" - default: - return "$" - } - } - - init?(currencyCode: String) { - let currencyName = Locales.posix.localizedString(forCurrencyCode: currencyCode) - - guard currencyName != nil, currencyName != unknownCurrencyName else { - return nil - } - - self.code = currencyCode - } - -} diff --git a/Sources/Afterpay/Model/CurrencyFormatter.swift b/Sources/Afterpay/Model/CurrencyFormatter.swift new file mode 100644 index 00000000..43a24309 --- /dev/null +++ b/Sources/Afterpay/Model/CurrencyFormatter.swift @@ -0,0 +1,25 @@ +// +// CurrencyFormatter.swift +// Afterpay +// +// Created by Adam Campbell on 16/10/20. +// Copyright © 2020 Afterpay. All rights reserved. +// + +import Foundation + +private let formatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.numberStyle = .currency + return formatter +}() + +struct CurrencyFormatter { + + let locale: Locale + + func string(from decimal: Decimal) -> String? { + formatter.string(from: decimal as NSDecimalNumber) + } + +} diff --git a/Sources/Afterpay/Model/PriceBreakdown.swift b/Sources/Afterpay/Model/PriceBreakdown.swift index 71356f95..26f8dd6c 100644 --- a/Sources/Afterpay/Model/PriceBreakdown.swift +++ b/Sources/Afterpay/Model/PriceBreakdown.swift @@ -8,12 +8,6 @@ import Foundation -private let formatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .currency - return formatter -}() - struct PriceBreakdown { enum BadgePlacement: Equatable { @@ -26,13 +20,11 @@ struct PriceBreakdown { init(totalAmount: Decimal) { let configuration = getConfiguration() + let formatter = CurrencyFormatter(locale: configuration?.locale ?? Locales.unitedStates) - formatter.currencySymbol = configuration?.currency.symbol - - let format: (Decimal) -> String? = { formatter.string(from: $0 as NSDecimalNumber) } - let formattedMinimum = configuration?.minimumAmount.flatMap(format) - let formattedMaximum = (configuration?.maximumAmount).flatMap(format) - let formattedPayment = format(totalAmount / 4) + let formattedMinimum = configuration?.minimumAmount.flatMap(formatter.string) + let formattedMaximum = (configuration?.maximumAmount).flatMap(formatter.string) + let formattedPayment = formatter.string(from: totalAmount / 4) let greaterThanZero = totalAmount > .zero let greaterThanOrEqualToMinimum = totalAmount >= (configuration?.minimumAmount ?? .zero) From ce2724fc31b0e34422c879180febf8c8e3f889f8 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 14:00:16 +1100 Subject: [PATCH 3/7] Create getLocale for retrieving a non optional locale --- Sources/Afterpay/Afterpay.swift | 6 ++++++ Sources/Afterpay/Model/PriceBreakdown.swift | 2 +- Sources/Afterpay/Views/SVGView.swift | 4 +--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/Afterpay/Afterpay.swift b/Sources/Afterpay/Afterpay.swift index ff8b8906..e4184490 100644 --- a/Sources/Afterpay/Afterpay.swift +++ b/Sources/Afterpay/Afterpay.swift @@ -85,6 +85,12 @@ func getConfiguration() -> Configuration? { configuration } +/// Retrieves the locale contained within the configuration otherwise defaulting to "en_US". +/// - Returns: The configured locale. +func getLocale() -> Locale { + configuration?.locale ?? Locales.unitedStates +} + /// Sets the Configuration object to use for rendering UI Components in the Afterpay SDK. /// - Parameter configuration: The configuration or nil to clear. public func setConfiguration(_ configuration: Configuration?) { diff --git a/Sources/Afterpay/Model/PriceBreakdown.swift b/Sources/Afterpay/Model/PriceBreakdown.swift index 26f8dd6c..1b798ebb 100644 --- a/Sources/Afterpay/Model/PriceBreakdown.swift +++ b/Sources/Afterpay/Model/PriceBreakdown.swift @@ -20,7 +20,7 @@ struct PriceBreakdown { init(totalAmount: Decimal) { let configuration = getConfiguration() - let formatter = CurrencyFormatter(locale: configuration?.locale ?? Locales.unitedStates) + let formatter = CurrencyFormatter(locale: getLocale()) let formattedMinimum = configuration?.minimumAmount.flatMap(formatter.string) let formattedMaximum = (configuration?.maximumAmount).flatMap(formatter.string) diff --git a/Sources/Afterpay/Views/SVGView.swift b/Sources/Afterpay/Views/SVGView.swift index 68e86b37..1030e5c5 100644 --- a/Sources/Afterpay/Views/SVGView.swift +++ b/Sources/Afterpay/Views/SVGView.swift @@ -24,9 +24,7 @@ final class SVGView: Macaw.SVGView { didSet { svgDidChange() } } - private var locale: Locale { - getConfiguration()?.locale ?? Locales.unitedStates - } + private var locale: Locale { getLocale() } init(svgConfiguration: SVGConfiguration) { self.svgConfiguration = svgConfiguration From ba0a18b7456eece2e164348ace46882204b3163b Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 15:46:28 +1100 Subject: [PATCH 4/7] Remove getLocale convenience --- Sources/Afterpay/Afterpay.swift | 6 ------ Sources/Afterpay/Model/PriceBreakdown.swift | 10 ++++++---- Sources/Afterpay/Views/SVGView.swift | 6 ++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Sources/Afterpay/Afterpay.swift b/Sources/Afterpay/Afterpay.swift index e4184490..ff8b8906 100644 --- a/Sources/Afterpay/Afterpay.swift +++ b/Sources/Afterpay/Afterpay.swift @@ -85,12 +85,6 @@ func getConfiguration() -> Configuration? { configuration } -/// Retrieves the locale contained within the configuration otherwise defaulting to "en_US". -/// - Returns: The configured locale. -func getLocale() -> Locale { - configuration?.locale ?? Locales.unitedStates -} - /// Sets the Configuration object to use for rendering UI Components in the Afterpay SDK. /// - Parameter configuration: The configuration or nil to clear. public func setConfiguration(_ configuration: Configuration?) { diff --git a/Sources/Afterpay/Model/PriceBreakdown.swift b/Sources/Afterpay/Model/PriceBreakdown.swift index 1b798ebb..46f082e9 100644 --- a/Sources/Afterpay/Model/PriceBreakdown.swift +++ b/Sources/Afterpay/Model/PriceBreakdown.swift @@ -20,11 +20,13 @@ struct PriceBreakdown { init(totalAmount: Decimal) { let configuration = getConfiguration() - let formatter = CurrencyFormatter(locale: getLocale()) + let formatter = configuration + .map { CurrencyFormatter(locale: $0.locale, currencyCode: $0.currencyCode) } + let format = { formatter?.string(from: $0) } - let formattedMinimum = configuration?.minimumAmount.flatMap(formatter.string) - let formattedMaximum = (configuration?.maximumAmount).flatMap(formatter.string) - let formattedPayment = formatter.string(from: totalAmount / 4) + let formattedMinimum = configuration?.minimumAmount.flatMap(format) + let formattedMaximum = (configuration?.maximumAmount).flatMap(format) + let formattedPayment = format(totalAmount / 4) let greaterThanZero = totalAmount > .zero let greaterThanOrEqualToMinimum = totalAmount >= (configuration?.minimumAmount ?? .zero) diff --git a/Sources/Afterpay/Views/SVGView.swift b/Sources/Afterpay/Views/SVGView.swift index 1030e5c5..c84242f4 100644 --- a/Sources/Afterpay/Views/SVGView.swift +++ b/Sources/Afterpay/Views/SVGView.swift @@ -16,15 +16,13 @@ import UIKit final class SVGView: Macaw.SVGView { - var svg: SVG { - svgConfiguration.svg(localizedFor: locale, withTraits: traitCollection) - } + var svg: SVG { svgConfiguration.svg(localizedFor: locale, withTraits: traitCollection) } var svgConfiguration: SVGConfiguration { didSet { svgDidChange() } } - private var locale: Locale { getLocale() } + private var locale: Locale { getConfiguration()?.locale ?? Locales.unitedStates } init(svgConfiguration: SVGConfiguration) { self.svgConfiguration = svgConfiguration From 627ed54c196a6458e5003974956d460577a66c39 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 15:47:13 +1100 Subject: [PATCH 5/7] Append currencyCode if currencyCode doesn't match locale --- Sources/Afterpay/Model/CurrencyFormatter.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/Afterpay/Model/CurrencyFormatter.swift b/Sources/Afterpay/Model/CurrencyFormatter.swift index 43a24309..0411c872 100644 --- a/Sources/Afterpay/Model/CurrencyFormatter.swift +++ b/Sources/Afterpay/Model/CurrencyFormatter.swift @@ -17,9 +17,18 @@ private let formatter: NumberFormatter = { struct CurrencyFormatter { let locale: Locale + let currencyCode: String func string(from decimal: Decimal) -> String? { - formatter.string(from: decimal as NSDecimalNumber) + formatter.currencyCode = currencyCode + + var formattedString = formatter.string(from: decimal as NSDecimalNumber) + + if locale.currencyCode != currencyCode { + formattedString?.append(" \(currencyCode)") + } + + return formattedString } } From 733334423ae82407805cd8fe3bc346f2430eef17 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 17:45:00 +1100 Subject: [PATCH 6/7] Update currency formatting logic to match Afterpay requirements --- .../Afterpay/Model/CurrencyFormatter.swift | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Sources/Afterpay/Model/CurrencyFormatter.swift b/Sources/Afterpay/Model/CurrencyFormatter.swift index 0411c872..438a006e 100644 --- a/Sources/Afterpay/Model/CurrencyFormatter.swift +++ b/Sources/Afterpay/Model/CurrencyFormatter.swift @@ -20,15 +20,19 @@ struct CurrencyFormatter { let currencyCode: String func string(from decimal: Decimal) -> String? { - formatter.currencyCode = currencyCode - - var formattedString = formatter.string(from: decimal as NSDecimalNumber) - - if locale.currencyCode != currencyCode { - formattedString?.append(" \(currencyCode)") + if locale == Locales.unitedStates || locale.currencyCode == currencyCode { + formatter.locale = locale + formatter.currencyCode = currencyCode + return formatter.string(from: decimal as NSDecimalNumber) + } else { + let currencyLocale = Locales.validSet.first { $0.currencyCode == currencyCode } + formatter.locale = currencyLocale + formatter.currencyCode = currencyCode + let formattedString = formatter.string(from: decimal as NSDecimalNumber) + return currencyLocale?.currencySymbol == locale.currencySymbol + ? formattedString?.appending(" \(currencyCode)") + : formattedString } - - return formattedString } } From 34afe625b5796ee5b9f3ff194ebd6c1feffefd36 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Fri, 16 Oct 2020 18:10:32 +1100 Subject: [PATCH 7/7] Test currency formatting --- Afterpay.xcodeproj/project.pbxproj | 4 + AfterpayTests/CurrencyFormatterTests.swift | 104 ++++++++++++++++++ .../Afterpay/Model/CurrencyFormatter.swift | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 AfterpayTests/CurrencyFormatterTests.swift diff --git a/Afterpay.xcodeproj/project.pbxproj b/Afterpay.xcodeproj/project.pbxproj index b5075b89..ed0c7591 100644 --- a/Afterpay.xcodeproj/project.pbxproj +++ b/Afterpay.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 6672982A25357D80001D1C5A /* SVGConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6672982925357D80001D1C5A /* SVGConfiguration.swift */; }; 667AD3542497121200BF94E5 /* CheckoutWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667AD3532497121100BF94E5 /* CheckoutWebViewController.swift */; }; 6689536C24C96CB5005090B4 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6689536B24C96CB5005090B4 /* Configuration.swift */; }; + 66C3F7FB25397A810086DD0A /* CurrencyFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C3F7FA25397A810086DD0A /* CurrencyFormatterTests.swift */; }; 66D685B224BD3FB900C7287C /* SwiftUIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D685B124BD3FB900C7287C /* SwiftUIWrapper.swift */; }; 66DAAC8B24E0CF0100127460 /* PriceBreakdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DAAC8A24E0CF0100127460 /* PriceBreakdown.swift */; }; 66DAAC8D24E109D200127460 /* PriceBreakdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DAAC8C24E109D200127460 /* PriceBreakdownTests.swift */; }; @@ -71,6 +72,7 @@ 66B57E55248F5C7D0020C642 /* Project-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Shared.xcconfig"; sourceTree = ""; }; 66B57E56248F5C7D0020C642 /* Project-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = ""; }; 66B57E57248F5C7D0020C642 /* Afterpay-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Afterpay-Release.xcconfig"; sourceTree = ""; }; + 66C3F7FA25397A810086DD0A /* CurrencyFormatterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyFormatterTests.swift; sourceTree = ""; }; 66D685B124BD3FB900C7287C /* SwiftUIWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIWrapper.swift; sourceTree = ""; }; 66DAAC8A24E0CF0100127460 /* PriceBreakdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceBreakdown.swift; sourceTree = ""; }; 66DAAC8C24E109D200127460 /* PriceBreakdownTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceBreakdownTests.swift; sourceTree = ""; }; @@ -142,6 +144,7 @@ isa = PBXGroup; children = ( 6635B95E24CAA9F000EBB3A6 /* ConfigurationTests.swift */, + 66C3F7FA25397A810086DD0A /* CurrencyFormatterTests.swift */, 665FC57B2488766C00A5A93E /* Info.plist */, 66DAAC8C24E109D200127460 /* PriceBreakdownTests.swift */, ); @@ -418,6 +421,7 @@ files = ( 6635B95F24CAA9F000EBB3A6 /* ConfigurationTests.swift in Sources */, 66DAAC8D24E109D200127460 /* PriceBreakdownTests.swift in Sources */, + 66C3F7FB25397A810086DD0A /* CurrencyFormatterTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/AfterpayTests/CurrencyFormatterTests.swift b/AfterpayTests/CurrencyFormatterTests.swift new file mode 100644 index 00000000..32862570 --- /dev/null +++ b/AfterpayTests/CurrencyFormatterTests.swift @@ -0,0 +1,104 @@ +// +// CurrencyFormatterTests.swift +// AfterpayTests +// +// Created by Adam Campbell on 16/10/20. +// Copyright © 2020 Afterpay. All rights reserved. +// + +@testable import Afterpay +import XCTest + +class CurrencyFormatterTests: XCTestCase { + + func testAustraliaLocale() { + let formatter: (String?) -> CurrencyFormatter = { currencyCode in + CurrencyFormatter(locale: Locales.australia, currencyCode: currencyCode!) + } + + let audFormatter = formatter(Locales.australia.currencyCode) + let cadFormatter = formatter(Locales.canada.currencyCode) + let gbpFormatter = formatter(Locales.greatBritain.currencyCode) + let nzdFormatter = formatter(Locales.newZealand.currencyCode) + let usdFormatter = formatter(Locales.unitedStates.currencyCode) + + XCTAssertEqual(audFormatter.string(from: 120), "$120.00") + XCTAssertEqual(cadFormatter.string(from: 120), "$120.00 CAD") + XCTAssertEqual(gbpFormatter.string(from: 120), "£120.00") + XCTAssertEqual(nzdFormatter.string(from: 120), "$120.00 NZD") + XCTAssertEqual(usdFormatter.string(from: 120), "$120.00 USD") + } + + func testCanadaLocale() { + let formatter: (String?) -> CurrencyFormatter = { currencyCode in + CurrencyFormatter(locale: Locales.canada, currencyCode: currencyCode!) + } + + let audFormatter = formatter(Locales.australia.currencyCode) + let cadFormatter = formatter(Locales.canada.currencyCode) + let gbpFormatter = formatter(Locales.greatBritain.currencyCode) + let nzdFormatter = formatter(Locales.newZealand.currencyCode) + let usdFormatter = formatter(Locales.unitedStates.currencyCode) + + XCTAssertEqual(audFormatter.string(from: 120), "$120.00 AUD") + XCTAssertEqual(cadFormatter.string(from: 120), "$120.00") + XCTAssertEqual(gbpFormatter.string(from: 120), "£120.00") + XCTAssertEqual(nzdFormatter.string(from: 120), "$120.00 NZD") + XCTAssertEqual(usdFormatter.string(from: 120), "$120.00 USD") + } + + func testGreatBritainLocale() { + let formatter: (String?) -> CurrencyFormatter = { currencyCode in + CurrencyFormatter(locale: Locales.greatBritain, currencyCode: currencyCode!) + } + + let audFormatter = formatter(Locales.australia.currencyCode) + let cadFormatter = formatter(Locales.canada.currencyCode) + let gbpFormatter = formatter(Locales.greatBritain.currencyCode) + let nzdFormatter = formatter(Locales.newZealand.currencyCode) + let usdFormatter = formatter(Locales.unitedStates.currencyCode) + + XCTAssertEqual(audFormatter.string(from: 120), "$120.00 AUD") + XCTAssertEqual(cadFormatter.string(from: 120), "$120.00 CAD") + XCTAssertEqual(gbpFormatter.string(from: 120), "£120.00") + XCTAssertEqual(nzdFormatter.string(from: 120), "$120.00 NZD") + XCTAssertEqual(usdFormatter.string(from: 120), "$120.00 USD") + } + + func testNewZealandLocale() { + let formatter: (String?) -> CurrencyFormatter = { currencyCode in + CurrencyFormatter(locale: Locales.newZealand, currencyCode: currencyCode!) + } + + let audFormatter = formatter(Locales.australia.currencyCode) + let cadFormatter = formatter(Locales.canada.currencyCode) + let gbpFormatter = formatter(Locales.greatBritain.currencyCode) + let nzdFormatter = formatter(Locales.newZealand.currencyCode) + let usdFormatter = formatter(Locales.unitedStates.currencyCode) + + XCTAssertEqual(audFormatter.string(from: 120), "$120.00 AUD") + XCTAssertEqual(cadFormatter.string(from: 120), "$120.00 CAD") + XCTAssertEqual(gbpFormatter.string(from: 120), "£120.00") + XCTAssertEqual(nzdFormatter.string(from: 120), "$120.00") + XCTAssertEqual(usdFormatter.string(from: 120), "$120.00 USD") + } + + func testUnitedStatesLocale() { + let formatter: (String?) -> CurrencyFormatter = { currencyCode in + CurrencyFormatter(locale: Locales.unitedStates, currencyCode: currencyCode!) + } + + let audFormatter = formatter(Locales.australia.currencyCode) + let cadFormatter = formatter(Locales.canada.currencyCode) + let gbpFormatter = formatter(Locales.greatBritain.currencyCode) + let nzdFormatter = formatter(Locales.newZealand.currencyCode) + let usdFormatter = formatter(Locales.unitedStates.currencyCode) + + XCTAssertEqual(audFormatter.string(from: 120), "A$120.00") + XCTAssertEqual(cadFormatter.string(from: 120), "CA$120.00") + XCTAssertEqual(gbpFormatter.string(from: 120), "£120.00") + XCTAssertEqual(nzdFormatter.string(from: 120), "NZ$120.00") + XCTAssertEqual(usdFormatter.string(from: 120), "$120.00") + } + +} diff --git a/Sources/Afterpay/Model/CurrencyFormatter.swift b/Sources/Afterpay/Model/CurrencyFormatter.swift index 438a006e..46e1c17a 100644 --- a/Sources/Afterpay/Model/CurrencyFormatter.swift +++ b/Sources/Afterpay/Model/CurrencyFormatter.swift @@ -29,7 +29,7 @@ struct CurrencyFormatter { formatter.locale = currencyLocale formatter.currencyCode = currencyCode let formattedString = formatter.string(from: decimal as NSDecimalNumber) - return currencyLocale?.currencySymbol == locale.currencySymbol + return currencyLocale?.currencySymbol == Locales.unitedStates.currencySymbol ? formattedString?.appending(" \(currencyCode)") : formattedString }