Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Improve restore #42

Merged
merged 2 commits into from
Nov 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
excluded:
disabled_rules:
- xctfail_message
- nesting
file_length:
- 600 # warning
- 1000 # error
Expand Down
31 changes: 17 additions & 14 deletions Sources/InAppPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public protocol InAppPurchaseProvidable {
func addTransactionObserver(fallbackHandler: InAppPurchase.PurchaseHandler?)
func removeTransactionObserver()
func fetchProduct(productIdentifiers: Set<String>, handler: ((_ result: Result<[Product], InAppPurchase.Error>) -> Void)?)
func restore(handler: ((_ result: Result<Void, InAppPurchase.Error>) -> Void)?)
func restore(handler: ((_ result: Result<Set<String>, InAppPurchase.Error>) -> Void)?)
func purchase(productIdentifier: String, handler: InAppPurchase.PurchaseHandler?)
}

Expand All @@ -35,10 +35,14 @@ final public class InAppPurchase {
case unknown
}

public enum PaymentState {
case purchased(transaction: PaymentTransaction)
case deferred
case restored
public struct PaymentState {
public enum State: Equatable {
case purchased
case deferred
case restored
}
let state: State
let transaction: PaymentTransaction
}

public static let `default` = InAppPurchase()
Expand Down Expand Up @@ -98,13 +102,17 @@ extension InAppPurchase: InAppPurchaseProvidable {
}
}

public func restore(handler: ((_ result: Result<Void, InAppPurchase.Error>) -> Void)?) {
paymentProvider.restoreCompletedTransactions { (_, error) in
public func restore(handler: ((_ result: Result<Set<String>, InAppPurchase.Error>) -> Void)?) {
paymentProvider.restoreCompletedTransactions { (queue, error) in
if let error = error {
handler?(.failure(error))
return
}
handler?(.success(()))
let productIds = queue
.transactions
.filter({ $0.transactionState == .restored })
.map({ $0.payment.productIdentifier })
handler?(.success(Set<String>(productIds)))
}
}

Expand Down Expand Up @@ -157,11 +165,6 @@ extension InAppPurchase.Error: Equatable {

extension InAppPurchase.PaymentState: Equatable {
public static func == (lhs: InAppPurchase.PaymentState, rhs: InAppPurchase.PaymentState) -> Bool {
switch (lhs, rhs) {
case (.purchased(let transaction1), .purchased(let transaction2)): return transaction1.transactionIdentifier == transaction2.transactionIdentifier
case (.deferred, .deferred): return true
case (.restored, .restored): return true
default: return false
}
return lhs.state == rhs.state && lhs.transaction.transactionIdentifier == rhs.transaction.transactionIdentifier
}
}
6 changes: 3 additions & 3 deletions Sources/Internal/Internal+InAppPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ extension InAppPurchase {
// Do nothing
break
case .purchased:
handler?(.success(.purchased(transaction: Internal.PaymentTransaction(transaction))))
handler?(.success(.init(state: .purchased, transaction: Internal.PaymentTransaction(transaction))))
case .restored:
handler?(.success(.restored))
handler?(.success(.init(state: .restored, transaction: Internal.PaymentTransaction(transaction))))
case .deferred:
handler?(.success(.deferred))
handler?(.success(.init(state: .deferred, transaction: Internal.PaymentTransaction(transaction))))
case .failed:
handler?(.failure(InAppPurchase.Error(error: transaction.error)))
@unknown default:
Expand Down
4 changes: 2 additions & 2 deletions Tests/InAppPurchaseIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class InAppPurchaseIntegrationTests: XCTestCase {
iap.addTransactionObserver(fallbackHandler: { (result) in
switch result {
case .success(let state):
switch state {
switch state.state {
case .purchased:
break
default:
Expand All @@ -43,7 +43,7 @@ final class InAppPurchaseIntegrationTests: XCTestCase {
iap.purchase(productIdentifier: "PRODUCT_001") { (result) in
switch result {
case .success(let state):
XCTAssertEqual(state, .deferred)
XCTAssertEqual(state.state, .deferred)
case .failure:
XCTFail()
}
Expand Down
65 changes: 35 additions & 30 deletions Tests/InAppPurchaseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class InAppPurchaseTests: XCTestCase {
}

func testInAppPurchasePaymentStateEqutable() {
XCTAssertEqual(InAppPurchase.PaymentState.deferred, InAppPurchase.PaymentState.deferred)
XCTAssertEqual(InAppPurchase.PaymentState.restored, InAppPurchase.PaymentState.restored)
XCTAssertNotEqual(InAppPurchase.PaymentState.deferred, InAppPurchase.PaymentState.restored)
XCTAssertEqual(InAppPurchase.PaymentState.State.deferred, InAppPurchase.PaymentState.State.deferred)
XCTAssertEqual(InAppPurchase.PaymentState.State.restored, InAppPurchase.PaymentState.State.restored)
XCTAssertNotEqual(InAppPurchase.PaymentState.State.deferred, InAppPurchase.PaymentState.State.restored)

let transaction1 = Internal.PaymentTransaction(StubPaymentTransaction(
transactionIdentifier: "TRANSACTION_001",
Expand All @@ -55,8 +55,8 @@ class InAppPurchaseTests: XCTestCase {
payment: StubPayment(productIdentifier: "PRODUCT_001"),
error: nil
))
XCTAssertEqual(InAppPurchase.PaymentState.purchased(transaction: transaction1), InAppPurchase.PaymentState.purchased(transaction: transaction2))
XCTAssertNotEqual(InAppPurchase.PaymentState.purchased(transaction: transaction1), InAppPurchase.PaymentState.purchased(transaction: transaction3))
XCTAssertEqual(InAppPurchase.PaymentState(state: .purchased, transaction: transaction1), InAppPurchase.PaymentState(state: .purchased, transaction: transaction2))
XCTAssertNotEqual(InAppPurchase.PaymentState(state: .purchased, transaction: transaction1), InAppPurchase.PaymentState(state: .purchased, transaction: transaction3))
}

func testCanMakePayments() {
Expand Down Expand Up @@ -125,7 +125,7 @@ class InAppPurchaseTests: XCTestCase {
handler: { (result) in
switch result {
case .success(let state):
XCTAssertEqual(state, InAppPurchase.PaymentState.purchased(transaction: Internal.PaymentTransaction(transaction)))
XCTAssertEqual(state, InAppPurchase.PaymentState(state: .purchased, transaction: Internal.PaymentTransaction(transaction)))
case .failure:
XCTFail()
}
Expand Down Expand Up @@ -245,17 +245,31 @@ class InAppPurchaseTests: XCTestCase {
func testRestore() {
let expectation = self.expectation()
let productProvider = StubProductProvider()
let queue = StubPaymentQueue()
let payment = StubPayment(productIdentifier: "PRODUCT_001")
let transaction1 = StubPaymentTransaction(
transactionIdentifier: "TRANSACTION_001",
transactionState: .restored,
original: nil,
payment: payment,
error: nil
)
let transaction2 = StubPaymentTransaction(
transactionIdentifier: "TRANSACTION_002",
transactionState: .purchased,
original: nil,
payment: payment,
error: nil
)
let queue = StubPaymentQueue(transactions: [transaction1, transaction2])
let paymentProvider = StubPaymentProvider(restoreHandler: { (handler) in
handler(queue, nil)
})

let iap = InAppPurchase(product: productProvider, payment: paymentProvider)
iap.restore { (result) in
switch result {
case .success:
// Do nothing, this is success.
break
case .success(let productIds):
XCTAssertEqual(productIds, ["PRODUCT_001"])
case .failure:
XCTFail()
}
Expand Down Expand Up @@ -311,12 +325,9 @@ class InAppPurchaseTests: XCTestCase {
iap.purchase(productIdentifier: "PRODUCT_001", handler: { (result) in
switch result {
case .success(let state):
if case let .purchased(transaction) = state {
XCTAssertEqual(transaction.transactionIdentifier, "TRANSACTION_001")
XCTAssertEqual(transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
} else {
XCTFail()
}
XCTAssertEqual(state.state, .purchased)
XCTAssertEqual(state.transaction.transactionIdentifier, "TRANSACTION_001")
XCTAssertEqual(state.transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
case .failure:
XCTFail()
}
Expand Down Expand Up @@ -415,12 +426,9 @@ class InAppPurchaseTests: XCTestCase {
let purchaseHandler: InAppPurchase.PurchaseHandler = { result in
switch result {
case .success(let state):
if case let .purchased(transaction) = state {
XCTAssertEqual(transaction.transactionIdentifier, "TRANSACTION_001")
XCTAssertEqual(transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
} else {
XCTFail()
}
XCTAssertEqual(state.state, .purchased)
XCTAssertEqual(state.transaction.transactionIdentifier, "TRANSACTION_001")
XCTAssertEqual(state.transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
default:
XCTFail()
}
Expand Down Expand Up @@ -486,12 +494,9 @@ class InAppPurchaseTests: XCTestCase {
InAppPurchase.handle(transaction: transaction, handler: { result in
switch result {
case .success(let state):
if case let .purchased(transaction) = state {
XCTAssertEqual(transaction.transactionIdentifier, "TRANSACTION_001")
XCTAssertEqual(transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
} else {
XCTFail()
}
XCTAssertEqual(state.state, .purchased)
XCTAssertEqual(state.transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
XCTAssertEqual(state.transaction.originalTransactionIdentifier, "ORIGINAL_TRANSACTION_001")
case .failure:
XCTFail()
}
Expand All @@ -512,7 +517,7 @@ class InAppPurchaseTests: XCTestCase {
InAppPurchase.handle(transaction: transaction, handler: { result in
switch result {
case .success(let state):
XCTAssertEqual(state, .restored)
XCTAssertEqual(state.state, .restored)
case .failure:
XCTFail()
}
Expand All @@ -533,7 +538,7 @@ class InAppPurchaseTests: XCTestCase {
InAppPurchase.handle(transaction: transaction, handler: { result in
switch result {
case .success(let state):
XCTAssertEqual(state, .deferred)
XCTAssertEqual(state.state, .deferred)
case .failure:
XCTFail()
}
Expand Down
27 changes: 16 additions & 11 deletions Tests/PaymentProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,29 @@ class PaymentProviderTests: XCTestCase {
func testRestore() {
let restoreExpectation = self.expectation()
let finishExepextation = self.expectation()
let queue = StubPaymentQueue(restoreCompletedTransactionsHandler: {
restoreExpectation.fulfill()
}, finishTransactionHandler: { _ in
finishExepextation.fulfill()
})
let provider = PaymentProvider(paymentQueue: queue)
let expectation = self.expectation()
provider.restoreCompletedTransactions { _, error in
XCTAssertNil(error)
expectation.fulfill()
}
let payment = StubPayment(productIdentifier: "PAYMENT_001")
let transaction = StubPaymentTransaction(
transactionIdentifier: "TRANSACTION_001",
transactionState: .restored,
original: nil,
payment: payment
)
let queue = StubPaymentQueue(
transactions: [transaction],
restoreCompletedTransactionsHandler: {
restoreExpectation.fulfill()
},
finishTransactionHandler: { _ in
finishExepextation.fulfill()
})
let provider = PaymentProvider(paymentQueue: queue)
let expectation = self.expectation()
provider.restoreCompletedTransactions { queue, error in
XCTAssertNil(error)
XCTAssertEqual(queue.transactions.map({ $0.transactionIdentifier }), ["TRANSACTION_001"])
XCTAssertEqual(queue.transactions.map({ $0.payment.productIdentifier }), ["PAYMENT_001"])
expectation.fulfill()
}
// Maybe updateTransactions is called and then restore completed method is called.
provider.paymentQueue(queue, updatedTransactions: [transaction])
provider.paymentQueueRestoreCompletedTransactionsFinished(queue)
Expand Down
6 changes: 3 additions & 3 deletions Tests/Stubs/StubInAppPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ final class StubInAppPurchase: InAppPurchaseProvidable {
private let _addTransactionObserverHandler: ((_ fallbackHandler: InAppPurchase.PurchaseHandler?) -> Void)?
private let _removeTransactionObserverHandler: (() -> Void)?
private let _fetchProductHandler: ((_ productIdentifiers: Set<String>, _ handler: ((_ result: Result<[Product], InAppPurchase.Error>) -> Void)?) -> Void)?
private let _restoreHandler: ((_ handler: ((_ result: Result<Void, InAppPurchase.Error>) -> Void)?) -> Void)?
private let _restoreHandler: ((_ handler: ((_ result: Result<Set<String>, InAppPurchase.Error>) -> Void)?) -> Void)?
private let _purchaseHandler: ((_ productIdentifier: String, _ handler: InAppPurchase.PurchaseHandler?) -> Void)?

init(canMakePayments: Bool = true,
setShouldAddStorePayementHandler: ((_ shouldAddStorePaymentHandler: ((Product) -> Bool)?, _ handler: InAppPurchase.PurchaseHandler?) -> Void)? = nil,
addTransactionObserverHandler: ((_ fallbackHandler: InAppPurchase.PurchaseHandler?) -> Void)? = nil,
removeTransactionObserverHandler: (() -> Void)? = nil,
fetchProductHandler: ((_ productIdentifiers: Set<String>, _ handler: ((_ result: Result<[Product], InAppPurchase.Error>) -> Void)?) -> Void)? = nil,
restoreHandler: ((_ handler: ((_ result: Result<Void, InAppPurchase.Error>) -> Void)?) -> Void)? = nil,
restoreHandler: ((_ handler: ((_ result: Result<Set<String>, InAppPurchase.Error>) -> Void)?) -> Void)? = nil,
purchaseHandler: ((_ productIdentifier: String, _ handler: InAppPurchase.PurchaseHandler?) -> Void)? = nil) {

self._canMakePayments = canMakePayments
Expand Down Expand Up @@ -54,7 +54,7 @@ final class StubInAppPurchase: InAppPurchaseProvidable {
_fetchProductHandler?(productIdentifiers, handler)
}

func restore(handler: ((_ result: Result<Void, InAppPurchase.Error>) -> Void)?) {
func restore(handler: ((_ result: Result<Set<String>, InAppPurchase.Error>) -> Void)?) {
_restoreHandler?(handler)
}

Expand Down
7 changes: 7 additions & 0 deletions Tests/Stubs/StubPaymentQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@ import StoreKit

final class StubPaymentQueue: SKPaymentQueue {
private static var _canMakePayments: Bool = false
private let _transactions: [StubPaymentTransaction]
private let _addObserverHandler: ((_ observer: SKPaymentTransactionObserver) -> Void)?
private let _removeObserverHandler: ((_ observer: SKPaymentTransactionObserver) -> Void)?
private let _addPaymentHandler: ((_ payment: SKPayment) -> Void)?
private let _restoreCompletedTransactionsHandler: (() -> Void)?
private let _finishTransactionHandler: ((_ transaction: SKPaymentTransaction) -> Void)?

init(canMakePayments: Bool = true,
transactions: [StubPaymentTransaction] = [],
addObserverHandler: ((_ observer: SKPaymentTransactionObserver) -> Void)? = nil,
removeObserverHandler: ((_ observer: SKPaymentTransactionObserver) -> Void)? = nil,
addPaymentHandler: ((_ payment: SKPayment) -> Void)? = nil,
restoreCompletedTransactionsHandler: (() -> Void)? = nil,
finishTransactionHandler: ((_ transaction: SKPaymentTransaction) -> Void)? = nil) {

StubPaymentQueue._canMakePayments = canMakePayments
self._transactions = transactions
self._addObserverHandler = addObserverHandler
self._removeObserverHandler = removeObserverHandler
self._addPaymentHandler = addPaymentHandler
Expand Down Expand Up @@ -56,4 +59,8 @@ final class StubPaymentQueue: SKPaymentQueue {
override func finishTransaction(_ transaction: SKPaymentTransaction) {
_finishTransactionHandler?(transaction)
}

override var transactions: [SKPaymentTransaction] {
return self._transactions
}
}