Skip to content

Commit b020ff5

Browse files
committed
Added a bunch more unit tests
1 parent 856e872 commit b020ff5

File tree

7 files changed

+283
-67
lines changed

7 files changed

+283
-67
lines changed

Sources/Purchasing/ProductsManager.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ import StoreKit
1717

1818
// MARK: -
1919

20-
struct PriceFormattingRuleSetProvider {
21-
let priceFormattingRuleSet: () -> PriceFormattingRuleSet?
22-
23-
static let empty = PriceFormattingRuleSetProvider(
24-
priceFormattingRuleSet: { nil }
25-
)
26-
}
27-
2820
/// Basic implemenation of a `ProductsManagerType`
2921
class ProductsManager: NSObject, ProductsManagerType {
3022

@@ -51,6 +43,7 @@ class ProductsManager: NSObject, ProductsManagerType {
5143
priceFormattingRuleSetProvider: PriceFormattingRuleSetProvider = .empty
5244
) {
5345
self.productsFetcherSK1 = ProductsFetcherSK1(productsRequestFactory: productsRequestFactory,
46+
priceFormattingRuleSetProvider: priceFormattingRuleSetProvider,
5447
requestTimeout: requestTimeout)
5548
self.diagnosticsTracker = diagnosticsTracker
5649
self.systemInfo = systemInfo
@@ -176,6 +169,15 @@ extension ProductsManagerType {
176169

177170
}
178171

172+
// MARK: -
173+
struct PriceFormattingRuleSetProvider {
174+
let priceFormattingRuleSet: () -> PriceFormattingRuleSet?
175+
176+
static let empty = PriceFormattingRuleSetProvider(
177+
priceFormattingRuleSet: { nil }
178+
)
179+
}
180+
179181
// MARK: -
180182

181183
// @unchecked because:

Sources/Purchasing/SimulatedStore/WebBillingProduct+SimulatedStoreProduct.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extension WebBillingProductsResponse.Product {
2121
if let priceFormatterProvider = self._priceFormatterProvider {
2222
return priceFormatterProvider
2323
} else {
24-
let provider = PriceFormatterProvider(priceFormattingRuleSet: nil)
24+
let provider = PriceFormatterProvider()
2525
self._priceFormatterProvider = provider
2626
return provider
2727
}

Sources/Purchasing/StoreKit1/ProductsFetcherSK1.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final class ProductsFetcherSK1: NSObject {
2020

2121
let requestTimeout: TimeInterval
2222
private let productsRequestFactory: ProductsRequestFactory
23+
private let priceFormattingRuleSetProvider: PriceFormattingRuleSetProvider
2324

2425
// Note: these 3 must be used only inside `queue` to be thread-safe.
2526
private var cachedProductsByIdentifier: [String: SK1Product] = [:]
@@ -35,8 +36,10 @@ final class ProductsFetcherSK1: NSObject {
3536
/// - Retries up to ``Self.numberOfRetries``
3637
/// - Timeout specified by this parameter
3738
init(productsRequestFactory: ProductsRequestFactory = ProductsRequestFactory(),
39+
priceFormattingRuleSetProvider: PriceFormattingRuleSetProvider = .empty,
3840
requestTimeout: TimeInterval) {
3941
self.productsRequestFactory = productsRequestFactory
42+
self.priceFormattingRuleSetProvider = priceFormattingRuleSetProvider
4043
self.requestTimeout = requestTimeout
4144
}
4245

@@ -57,8 +60,13 @@ final class ProductsFetcherSK1: NSObject {
5760
threshold: .productRequest,
5861
message: Strings.storeKit.sk1_product_request_too_slow,
5962
work: { completion in
60-
self.sk1Products(withIdentifiers: identifiers) { skProducts in
61-
completion(skProducts.map { Set($0.map(SK1StoreProduct.init)) })
63+
self.sk1Products(withIdentifiers: identifiers) { [weak self] skProducts in
64+
completion(skProducts.map { Set($0.map {
65+
SK1StoreProduct(
66+
sk1Product: $0,
67+
priceFormatterProvider: .init(priceFormattingRuleSet: self?.priceFormattingRuleSetProvider.priceFormattingRuleSet())
68+
)})
69+
})
6270
}
6371
},
6472
result: completion

Sources/Purchasing/StoreKitAbstractions/SK1StoreProduct.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ import StoreKit
1515

1616
internal struct SK1StoreProduct: StoreProductType {
1717

18-
init(sk1Product: SK1Product) {
18+
init(sk1Product: SK1Product, priceFormatterProvider: PriceFormatterProvider = .init()) {
1919
self.underlyingSK1Product = sk1Product
20+
self.priceFormatterProvider = priceFormatterProvider
2021
}
2122

2223
let underlyingSK1Product: SK1Product
23-
private let priceFormatterProvider: PriceFormatterProvider = .init(priceFormattingRuleSet: nil) // todo rick: also implement for SK1?
24+
private let priceFormatterProvider: PriceFormatterProvider
2425

2526
var productCategory: StoreProduct.ProductCategory {
2627
guard #available(iOS 11.2, macOS 10.13.2, tvOS 11.2, watchOS 6.2, *) else {

Sources/Purchasing/StoreKitAbstractions/Test Data/TestStoreProduct.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public struct TestStoreProduct {
9595

9696
// swiftlint:enable missing_docs
9797

98-
private let priceFormatterProvider: PriceFormatterProvider = .init(priceFormattingRuleSet: nil) // todo rick?
98+
private let priceFormatterProvider: PriceFormatterProvider = .init()
9999

100100
}
101101

Tests/StoreKitUnitTests/PriceFormatterProviderTests.swift

Lines changed: 183 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
2525
override func setUp() {
2626
super.setUp()
2727

28-
self.priceFormatterProvider = PriceFormatterProvider(priceFormattingRuleSet: nil)
28+
self.priceFormatterProvider = PriceFormatterProvider()
2929
}
3030

3131
func testReturnsCachedPriceFormatterForSK1() {
@@ -45,6 +45,15 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
4545

4646
expect(firstPriceFormatter) === secondPriceFormatter
4747
}
48+
49+
func testReturnsCachedPriceFormatterForWebProducts() throws {
50+
let currencyCode = "USD"
51+
let firstPriceFormatter = self.priceFormatterProvider.priceFormatterForWebProducts(withCurrencyCode: currencyCode)
52+
53+
let secondPriceFormatter = self.priceFormatterProvider.priceFormatterForWebProducts(withCurrencyCode: currencyCode)
54+
55+
expect(firstPriceFormatter) === secondPriceFormatter
56+
}
4857

4958
func testSk1PriceFormatterUsesCurrentStorefront() async throws {
5059
self.testSession.locale = Locale(identifier: "es_ES")
@@ -71,6 +80,59 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
7180
priceFormatter = try XCTUnwrap(storeProduct.priceFormatter)
7281
expect(priceFormatter.currencyCode) == "USD"
7382
}
83+
84+
func testSk1PriceFormatterCurrencySymbolOverriding() async throws {
85+
priceFormatterProvider = .init(
86+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
87+
"EUR": .init(
88+
zero: "zero",
89+
one: "one",
90+
two: "two",
91+
few: "few",
92+
many: "many",
93+
other: "other"
94+
)
95+
])
96+
)
97+
98+
let priceFormatter = priceFormatterProvider.priceFormatterForSK1(
99+
with: .init(identifier: "nl_NL")
100+
)
101+
102+
expect(priceFormatter.currencyCode) == "EUR"
103+
expect(priceFormatter.currencySymbol) == ""
104+
XCTAssert(type(of: priceFormatter) == CurrencySymbolOverridingPriceFormatter.self)
105+
106+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 0)), "zero 0,00")
107+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 1)), "one 1,00")
108+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 2)), "two 2,00")
109+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 3)), "other 3,00")
110+
}
111+
112+
func testSk1PriceFormatterCurrencySymbolOverridingUsesCachedPriceFormatter() async throws {
113+
priceFormatterProvider = .init(
114+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
115+
"EUR": .init(
116+
zero: "zero",
117+
one: "one",
118+
two: "two",
119+
few: "few",
120+
many: "many",
121+
other: "other"
122+
)
123+
])
124+
)
125+
126+
let firstPriceFormatter = priceFormatterProvider.priceFormatterForSK1(
127+
with: .init(identifier: "nl_NL")
128+
)
129+
130+
let secondPriceFormatter = priceFormatterProvider.priceFormatterForSK1(
131+
with: .init(identifier: "nl_NL")
132+
)
133+
134+
expect(firstPriceFormatter) == secondPriceFormatter
135+
}
74136

75137
@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
76138
func testSk2PriceFormatterUsesCurrentStorefront() async throws {
@@ -97,31 +159,24 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
97159

98160
@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
99161
func testSk2PriceFormatterCurrencySymbolOverriding() async throws {
100-
try AvailabilityChecks.iOS16APIAvailableOrSkipTest()
101-
102-
self.testSession.locale = Locale(identifier: "nl_NL")
103-
try await self.changeStorefront("NLD")
104-
105-
let sk2Fetcher = ProductsFetcherSK2(
106-
priceFormattingRuleSetProvider: .init(
107-
priceFormattingRuleSet: {
108-
.init(currencySymbolOverrides: [
109-
"EUR": .init(
110-
zero: "zero",
111-
one: "one",
112-
two: "two",
113-
few: "few",
114-
many: "many",
115-
other: "other"
116-
)
117-
])
118-
}
119-
)
120-
)
121-
122-
let storeProduct = try await sk2Fetcher.product(withIdentifier: Self.productID)
123-
124-
let priceFormatter = try XCTUnwrap(storeProduct.priceFormatter)
162+
priceFormatterProvider = .init(
163+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
164+
"EUR": .init(
165+
zero: "zero",
166+
one: "one",
167+
two: "two",
168+
few: "few",
169+
many: "many",
170+
other: "other"
171+
)
172+
])
173+
)
174+
175+
let priceFormatter = priceFormatterProvider.priceFormatterForSK2(
176+
withCurrencyCode: "EUR",
177+
locale: .init(identifier: "nl_NL")
178+
)
179+
125180
expect(priceFormatter.currencyCode) == "EUR"
126181
expect(priceFormatter.currencySymbol) == ""
127182
XCTAssert(type(of: priceFormatter) == CurrencySymbolOverridingPriceFormatter.self)
@@ -134,31 +189,24 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
134189

135190
@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
136191
func testSk2PriceFormatterCurrencySymbolOverridingRomania() async throws {
137-
try AvailabilityChecks.iOS16APIAvailableOrSkipTest()
138-
139-
self.testSession.locale = Locale(identifier: "ro_RO")
140-
try await self.changeStorefront("ROU")
141-
142-
let sk2Fetcher = ProductsFetcherSK2(
143-
priceFormattingRuleSetProvider: .init(
144-
priceFormattingRuleSet: {
145-
.init(currencySymbolOverrides: [
146-
"RON": .init(
147-
zero: "lei",
148-
one: "leu",
149-
two: "lei",
150-
few: "lei",
151-
many: "lei",
152-
other: "lei"
153-
)
154-
])
155-
}
156-
)
157-
)
158-
159-
let storeProduct = try await sk2Fetcher.product(withIdentifier: Self.productID)
160-
161-
let priceFormatter = try XCTUnwrap(storeProduct.priceFormatter)
192+
priceFormatterProvider = .init(
193+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
194+
"RON": .init(
195+
zero: "lei",
196+
one: "leu",
197+
two: "lei",
198+
few: "lei",
199+
many: "lei",
200+
other: "lei"
201+
)
202+
])
203+
)
204+
205+
let priceFormatter = priceFormatterProvider.priceFormatterForSK2(
206+
withCurrencyCode: "RON",
207+
locale: .init(identifier: "ro_RO")
208+
)
209+
162210
expect(priceFormatter.currencyCode) == "RON"
163211
expect(priceFormatter.currencySymbol) == "RON"
164212
XCTAssert(type(of: priceFormatter) == CurrencySymbolOverridingPriceFormatter.self)
@@ -167,6 +215,90 @@ class PriceFormatterProviderTests: StoreKitConfigTestCase {
167215
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 1)), "1,00 leu")
168216
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 2)), "2,00 lei")
169217
}
218+
219+
@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
220+
func testSk2PriceFormatterCurrencySymbolOverridingUsesCachedPriceFormatter() async throws {
221+
priceFormatterProvider = .init(
222+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
223+
"EUR": .init(
224+
zero: "zero",
225+
one: "one",
226+
two: "two",
227+
few: "few",
228+
many: "many",
229+
other: "other"
230+
)
231+
])
232+
)
233+
234+
let firstPriceFormatter = priceFormatterProvider.priceFormatterForSK2(
235+
withCurrencyCode: "EUR",
236+
locale: .init(identifier: "nl_NL")
237+
)
238+
239+
let secondPriceFormatter = priceFormatterProvider.priceFormatterForSK2(
240+
withCurrencyCode: "EUR",
241+
locale: .init(identifier: "nl_NL")
242+
)
243+
244+
expect(firstPriceFormatter) == secondPriceFormatter
245+
}
246+
247+
func testWebProductsPriceFormatterCurrencySymbolOverriding() async throws {
248+
priceFormatterProvider = .init(
249+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
250+
"EUR": .init(
251+
zero: "zero",
252+
one: "one",
253+
two: "two",
254+
few: "few",
255+
many: "many",
256+
other: "other"
257+
)
258+
])
259+
)
260+
261+
let priceFormatter = priceFormatterProvider.priceFormatterForWebProducts(
262+
withCurrencyCode: "EUR",
263+
locale: Locale(identifier: "nl_NL")
264+
)
265+
266+
expect(priceFormatter.currencyCode) == "EUR"
267+
expect(priceFormatter.currencySymbol) == ""
268+
XCTAssert(type(of: priceFormatter) == CurrencySymbolOverridingPriceFormatter.self)
269+
270+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 0)), "zero 0,00")
271+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 1)), "one 1,00")
272+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 2)), "two 2,00")
273+
XCTAssertEqual(priceFormatter.string(from: NSNumber(integerLiteral: 3)), "other 3,00")
274+
}
275+
276+
func testWebProductsFormatterCurrencySymbolOverridingUsesCachedPriceFormatter() async throws {
277+
priceFormatterProvider = .init(
278+
priceFormattingRuleSet: .init(currencySymbolOverrides: [
279+
"EUR": .init(
280+
zero: "zero",
281+
one: "one",
282+
two: "two",
283+
few: "few",
284+
many: "many",
285+
other: "other"
286+
)
287+
])
288+
)
289+
290+
let firstPriceFormatter = priceFormatterProvider.priceFormatterForWebProducts(
291+
withCurrencyCode: "EUR",
292+
locale: Locale(identifier: "nl_NL")
293+
)
294+
295+
let secondPriceFormatter = priceFormatterProvider.priceFormatterForWebProducts(
296+
withCurrencyCode: "EUR",
297+
locale: Locale(identifier: "nl_NL")
298+
)
299+
300+
expect(firstPriceFormatter) == secondPriceFormatter
301+
}
170302
}
171303

172304
extension PriceFormattingRuleSetProvider {

0 commit comments

Comments
 (0)