Andrea Bizzotto 8 жил өмнө
parent
commit
1a240051fd

+ 5 - 6
SwiftyStoreKit-iOS-Demo/AppDelegate.swift

@@ -36,15 +36,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
         return true
     }
-    
+
     func completeIAPTransactions() {
-        
+
         SwiftyStoreKit.completeTransactions(atomically: true) { products in
-            
+
             for product in products {
-                
+
                 if product.transaction.transactionState == .purchased || product.transaction.transactionState == .restored {
-                    
+
                     if product.needsFinishTransaction {
                         // Deliver content from server, then:
                         SwiftyStoreKit.finishTransaction(product.transaction)
@@ -55,4 +55,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         }
     }
 }
-

+ 3 - 3
SwiftyStoreKit-iOS-Demo/NetworkActivityIndicatorManager.swift

@@ -27,15 +27,15 @@ import UIKit
 class NetworkActivityIndicatorManager: NSObject {
 
     private static var loadingCount = 0
-    
+
     class func networkOperationStarted() {
-        
+
         if loadingCount == 0 {
             UIApplication.shared.isNetworkActivityIndicatorVisible = true
         }
         loadingCount += 1
     }
-    
+
     class func networkOperationFinished() {
         if loadingCount > 0 {
             loadingCount -= 1

+ 41 - 47
SwiftyStoreKit-iOS-Demo/ViewController.swift

@@ -26,8 +26,8 @@ import UIKit
 import StoreKit
 import SwiftyStoreKit
 
-enum RegisteredPurchase : String {
-    
+enum RegisteredPurchase: String {
+
     case purchase1 = "purchase1"
     case purchase2 = "purchase2"
     case nonConsumablePurchase = "nonConsumablePurchase"
@@ -39,47 +39,47 @@ enum RegisteredPurchase : String {
 
 class ViewController: UIViewController {
 
-    let AppBundleId = "com.musevisions.iOS.SwiftyStoreKit"
-    
-    let Purchase1 = RegisteredPurchase.purchase1
-    let Purchase2 = RegisteredPurchase.autoRenewablePurchase
-    
+    let appBundleId = "com.musevisions.iOS.SwiftyStoreKit"
+
+    let purchase1 = RegisteredPurchase.purchase1
+    let purchase2 = RegisteredPurchase.autoRenewablePurchase
+
     // MARK: actions
     @IBAction func getInfo1() {
-        getInfo(Purchase1)
+        getInfo(purchase1)
     }
     @IBAction func purchase1() {
-        purchase(Purchase1)
+        purchase(purchase1)
     }
     @IBAction func verifyPurchase1() {
-        verifyPurchase(Purchase1)
+        verifyPurchase(purchase1)
     }
     @IBAction func getInfo2() {
-        getInfo(Purchase2)
+        getInfo(purchase2)
     }
     @IBAction func purchase2() {
-        purchase(Purchase2)
+        purchase(purchase2)
     }
     @IBAction func verifyPurchase2() {
-        verifyPurchase(Purchase2)
+        verifyPurchase(purchase2)
     }
 
     func getInfo(_ purchase: RegisteredPurchase) {
-        
+
         NetworkActivityIndicatorManager.networkOperationStarted()
-        SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchase.rawValue]) { result in
+        SwiftyStoreKit.retrieveProductsInfo([appBundleId + "." + purchase.rawValue]) { result in
             NetworkActivityIndicatorManager.networkOperationFinished()
-            
+
             self.showAlert(self.alertForProductRetrievalInfo(result))
         }
     }
-    
+
     func purchase(_ purchase: RegisteredPurchase) {
-        
+
         NetworkActivityIndicatorManager.networkOperationStarted()
-        SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchase.rawValue, atomically: true) { result in
+        SwiftyStoreKit.purchaseProduct(appBundleId + "." + purchase.rawValue, atomically: true) { result in
             NetworkActivityIndicatorManager.networkOperationFinished()
-            
+
             if case .success(let product) = result {
                 // Deliver content from server, then:
                 if product.needsFinishTransaction {
@@ -91,13 +91,13 @@ class ViewController: UIViewController {
             }
         }
     }
-    
+
     @IBAction func restorePurchases() {
-        
+
         NetworkActivityIndicatorManager.networkOperationStarted()
         SwiftyStoreKit.restorePurchases(atomically: true) { results in
             NetworkActivityIndicatorManager.networkOperationFinished()
-            
+
             for product in results.restoredProducts {
                 // Deliver content from server, then:
                 if product.needsFinishTransaction {
@@ -131,12 +131,12 @@ class ViewController: UIViewController {
 		let appleValidator = AppleReceiptValidator(service: .production)
 		SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
             NetworkActivityIndicatorManager.networkOperationFinished()
-            
+
             switch result {
             case .success(let receipt):
-              
+
                 let productId = self.AppBundleId + "." + purchase.rawValue
-                
+
                 // Specific behaviour for AutoRenewablePurchase
                 if purchase == .autoRenewablePurchase {
                     let purchaseResult = SwiftyStoreKit.verifySubscription(
@@ -145,15 +145,14 @@ class ViewController: UIViewController {
                         validUntil: Date()
                     )
                     self.showAlert(self.alertForVerifySubscription(purchaseResult))
-                }
-                else {
+                } else {
                     let purchaseResult = SwiftyStoreKit.verifyPurchase(
                         productId: productId,
                         inReceipt: receipt
                     )
                     self.showAlert(self.alertForVerifyPurchase(purchaseResult))
                 }
-                
+
             case .error(let error):
                 self.showAlert(self.alertForVerifyReceipt(result))
                 if case .noReceiptData = error {
@@ -178,14 +177,14 @@ class ViewController: UIViewController {
 
 // MARK: User facing alerts
 extension ViewController {
-    
+
     func alertWithTitle(_ title: String, message: String) -> UIAlertController {
-        
+
         let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
         alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
         return alert
     }
-    
+
     func showAlert(_ alert: UIAlertController) {
         guard let _ = self.presentedViewController else {
             self.present(alert, animated: true, completion: nil)
@@ -194,15 +193,13 @@ extension ViewController {
     }
 
     func alertForProductRetrievalInfo(_ result: RetrieveResults) -> UIAlertController {
-        
+
         if let product = result.retrievedProducts.first {
             let priceString = product.localizedPrice!
             return alertWithTitle(product.localizedTitle, message: "\(product.localizedDescription) - \(priceString)")
-        }
-        else if let invalidProductId = result.invalidProductIDs.first {
+        } else if let invalidProductId = result.invalidProductIDs.first {
             return alertWithTitle("Could not retrieve product info", message: "Invalid product identifier: \(invalidProductId)")
-        }
-        else {
+        } else {
             let errorString = result.error?.localizedDescription ?? "Unknown error. Please contact support"
             return alertWithTitle("Could not retrieve product info", message: errorString)
         }
@@ -234,18 +231,16 @@ extension ViewController {
             }
         }
     }
-    
+
     func alertForRestorePurchases(_ results: RestoreResults) -> UIAlertController {
 
         if results.restoreFailedProducts.count > 0 {
             print("Restore Failed: \(results.restoreFailedProducts)")
             return alertWithTitle("Restore failed", message: "Unknown error. Please contact support")
-        }
-        else if results.restoredProducts.count > 0 {
+        } else if results.restoredProducts.count > 0 {
             print("Restore Success: \(results.restoredProducts)")
             return alertWithTitle("Purchases Restored", message: "All purchases have been restored")
-        }
-        else {
+        } else {
             print("Nothing to Restore")
             return alertWithTitle("Nothing to restore", message: "No previous purchases were found")
         }
@@ -260,7 +255,7 @@ extension ViewController {
             return alertWithTitle("Receipt verified", message: "Receipt verified remotly")
         case .error(let error):
             print("Verify receipt Failed: \(error)")
-            switch (error) {
+            switch error {
             case .noReceiptData :
                 return alertWithTitle("Receipt verification", message: "No receipt data, application will try to get a new one. Try again.")
             default:
@@ -268,9 +263,9 @@ extension ViewController {
             }
         }
     }
-  
+
     func alertForVerifySubscription(_ result: VerifySubscriptionResult) -> UIAlertController {
-    
+
         switch result {
         case .purchased(let expiresDate):
             print("Product is valid until \(expiresDate)")
@@ -285,7 +280,7 @@ extension ViewController {
     }
 
     func alertForVerifyPurchase(_ result: VerifyPurchaseResult) -> UIAlertController {
-        
+
         switch result {
         case .purchased:
             print("Product is purchased")
@@ -308,4 +303,3 @@ extension ViewController {
     }
 
 }
-

+ 5 - 6
SwiftyStoreKit-macOS-Demo/AppDelegate.swift

@@ -32,15 +32,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
 
         completeIAPTransactions()
     }
-    
+
     func completeIAPTransactions() {
-        
+
         SwiftyStoreKit.completeTransactions(atomically: true) { products in
-            
+
             for product in products {
-                
+
                 if product.transaction.transactionState == .purchased || product.transaction.transactionState == .restored {
-                    
+
                     if product.needsFinishTransaction {
                         // Deliver content from server, then:
                         SwiftyStoreKit.finishTransaction(product.transaction)
@@ -51,4 +51,3 @@ class AppDelegate: NSObject, NSApplicationDelegate {
         }
     }
 }
-

+ 41 - 47
SwiftyStoreKit-macOS-Demo/ViewController.swift

@@ -26,48 +26,48 @@ import Cocoa
 import StoreKit
 import SwiftyStoreKit
 
-enum RegisteredPurchase : String {
-    
+enum RegisteredPurchase: String {
+
     case purchase1 = "purchase1"
     case purchase2 = "purchase2"
     case nonConsumablePurchase = "nonConsumablePurchase"
     case consumablePurchase = "consumablePurchase"
     case autoRenewablePurchase = "autoRenewablePurchase"
     case nonRenewingPurchase = "nonRenewingPurchase"
-    
+
 }
 
 class ViewController: NSViewController {
 
-    let AppBundleId = "com.musevisions.MacOS.SwiftyStoreKitDemo"
-    
-    let Purchase1 = RegisteredPurchase.purchase1
-    let Purchase2 = RegisteredPurchase.autoRenewablePurchase
+    let appBundleId = "com.musevisions.MacOS.SwiftyStoreKitDemo"
+
+    let purchase1 = RegisteredPurchase.purchase1
+    let purchase2 = RegisteredPurchase.autoRenewablePurchase
 
     // MARK: actions
     @IBAction func getInfo1(_ sender: Any?) {
-        getInfo(Purchase1)
+        getInfo(purchase1)
     }
     @IBAction func purchase1(_ sender: Any?) {
-        purchase(Purchase1)
+        purchase(purchase1)
     }
     @IBAction func verifyPurchase1(_ sender: Any?) {
-        verifyPurchase(Purchase1)
+        verifyPurchase(purchase1)
     }
 
     @IBAction func getInfo2(_ sender: Any?) {
-        getInfo(Purchase2)
+        getInfo(purchase2)
     }
     @IBAction func purchase2(_ sender: Any?) {
-        purchase(Purchase2)
+        purchase(purchase2)
     }
     @IBAction func verifyPurchase2(_ sender: Any?) {
-        verifyPurchase(Purchase2)
+        verifyPurchase(purchase2)
     }
 
     func getInfo(_ purchase: RegisteredPurchase) {
 
-        SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchase.rawValue]) { result in
+        SwiftyStoreKit.retrieveProductsInfo([appBundleId + "." + purchase.rawValue]) { result in
 
             self.showAlert(self.alertForProductRetrievalInfo(result))
         }
@@ -75,7 +75,7 @@ class ViewController: NSViewController {
 
     func purchase(_ purchase: RegisteredPurchase) {
 
-        SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchase.rawValue, atomically: true) { result in
+        SwiftyStoreKit.purchaseProduct(appBundleId + "." + purchase.rawValue, atomically: true) { result in
 
             if case .success(let product) = result {
                 // Deliver content from server, then:
@@ -93,7 +93,7 @@ class ViewController: NSViewController {
     @IBAction func restorePurchases(_ sender: Any?) {
 
         SwiftyStoreKit.restorePurchases(atomically: true) { results in
-            
+
             for product in results.restoredProducts {
                 // Deliver content from server, then:
                 if product.needsFinishTransaction {
@@ -122,15 +122,15 @@ class ViewController: NSViewController {
     }
 
     func verifyPurchase(_ purchase: RegisteredPurchase) {
-        
+
         let appleValidator = AppleReceiptValidator(service: .production)
         SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
-            
+
             switch result {
             case .success(let receipt):
-                
+
                 let productId = self.AppBundleId + "." + purchase.rawValue
-                
+
                 // Specific behaviour for AutoRenewablePurchase
                 if purchase == .autoRenewablePurchase {
                     let purchaseResult = SwiftyStoreKit.verifySubscription(
@@ -139,15 +139,14 @@ class ViewController: NSViewController {
                         validUntil: Date()
                     )
                     self.showAlert(self.alertForVerifySubscription(purchaseResult))
-                }
-                else {
+                } else {
                     let purchaseResult = SwiftyStoreKit.verifyPurchase(
                         productId: productId,
                         inReceipt: receipt
                     )
                     self.showAlert(self.alertForVerifyPurchase(purchaseResult))
                 }
-                            
+
             case .error(_):
                 self.showAlert(self.alertForVerifyReceipt(result))
             }
@@ -155,9 +154,9 @@ class ViewController: NSViewController {
     }
 
     func refreshReceipt() {
-        
+
         SwiftyStoreKit.refreshReceipt() { result in
-            
+
             self.showAlert(self.alertForRefreshReceipt(result))
         }
     }
@@ -166,9 +165,9 @@ class ViewController: NSViewController {
 
 // MARK: User facing alerts
 extension ViewController {
-    
+
     func alertWithTitle(_ title: String, message: String) -> NSAlert {
-        
+
         let alert: NSAlert = NSAlert()
         alert.messageText = title
         alert.informativeText = message
@@ -176,9 +175,9 @@ extension ViewController {
         return alert
     }
     func showAlert(_ alert: NSAlert, handler: ((NSModalResponse) -> Void)? = nil) {
-        
+
         if let window = NSApplication.shared().keyWindow {
-            alert.beginSheetModal(for: window)  { (response: NSModalResponse) in
+            alert.beginSheetModal(for: window) { (response: NSModalResponse) in
                 handler?(response)
             }
         } else {
@@ -188,20 +187,18 @@ extension ViewController {
     }
 
     func alertForProductRetrievalInfo(_ result: RetrieveResults) -> NSAlert {
-        
+
         if let product = result.retrievedProducts.first {
             let priceString = product.localizedPrice!
             return alertWithTitle(product.localizedTitle, message: "\(product.localizedDescription) - \(priceString)")
-        }
-        else if let invalidProductId = result.invalidProductIDs.first {
+        } else if let invalidProductId = result.invalidProductIDs.first {
             return alertWithTitle("Could not retrieve product info", message: "Invalid product identifier: \(invalidProductId)")
-        }
-        else {
+        } else {
             let errorString = result.error?.localizedDescription ?? "Unknown error. Please contact support"
             return alertWithTitle("Could not retrieve product info", message: errorString)
         }
     }
-    
+
     func alertForPurchaseResult(_ result: PurchaseResult) -> NSAlert? {
         switch result {
         case .success(let product):
@@ -222,23 +219,21 @@ extension ViewController {
             }
         }
     }
-    
+
     func alertForRestorePurchases(_ results: RestoreResults) -> NSAlert {
-        
+
         if results.restoreFailedProducts.count > 0 {
             print("Restore Failed: \(results.restoreFailedProducts)")
             return alertWithTitle("Restore failed", message: "Unknown error. Please contact support")
-        }
-        else if results.restoredProducts.count > 0 {
+        } else if results.restoredProducts.count > 0 {
             print("Restore Success: \(results.restoredProducts)")
             return alertWithTitle("Purchases Restored", message: "All purchases have been restored")
-        }
-        else {
+        } else {
             print("Nothing to Restore")
             return alertWithTitle("Nothing to restore", message: "No previous purchases were found")
         }
     }
-    
+
     func alertForVerifyReceipt(_ result: VerifyReceiptResult) -> NSAlert {
 
         switch result {
@@ -250,9 +245,9 @@ extension ViewController {
             return self.alertWithTitle("Receipt verification failed", message: "The application will exit to create receipt data. You must have signed the application with your developer id to test and be outside of XCode")
         }
     }
-    
+
     func alertForVerifySubscription(_ result: VerifySubscriptionResult) -> NSAlert {
-        
+
         switch result {
         case .purchased(let expiresDate):
             print("Product is valid until \(expiresDate)")
@@ -268,7 +263,7 @@ extension ViewController {
 
 
     func alertForVerifyPurchase(_ result: VerifyPurchaseResult) -> NSAlert {
-        
+
         switch result {
         case .purchased:
             print("Product is purchased")
@@ -278,7 +273,7 @@ extension ViewController {
             return alertWithTitle("Not purchased", message: "This product has never been purchased")
         }
     }
-    
+
     func alertForRefreshReceipt(_ result: RefreshReceiptResult) -> NSAlert {
         switch result {
         case .success(let receiptData):
@@ -291,4 +286,3 @@ extension ViewController {
     }
 
 }
-

+ 3 - 6
SwiftyStoreKit/AppleReceiptValidator.swift

@@ -101,17 +101,14 @@ public struct AppleReceiptValidator: ReceiptValidator {
 				if case .testReceipt = receiptStatus {
 					let sandboxValidator = AppleReceiptValidator(service: .sandbox)
 					sandboxValidator.validate(receipt: receipt, password: autoRenewPassword, completion: completion)
-				}
-				else {
+				} else {
 					if receiptStatus.isValid {
 						completion(.success(receipt: receiptInfo))
-					}
-					else {
+					} else {
 						completion(.error(error: .receiptInvalid(receipt: receiptInfo, status: receiptStatus)))
 					}
 				}
-			}
-			else {
+			} else {
 				completion(.error(error: .receiptInvalid(receipt: receiptInfo, status: ReceiptStatus.none)))
 			}
 		}

+ 12 - 13
SwiftyStoreKit/CompleteTransactionsController.swift

@@ -28,7 +28,7 @@ import StoreKit
 struct CompleteTransactions {
     let atomically: Bool
     let callback: ([Product]) -> ()
-    
+
     init(atomically: Bool, callback: @escaping ([Product]) -> ()) {
         self.atomically = atomically
         self.callback = callback
@@ -36,7 +36,7 @@ struct CompleteTransactions {
 }
 
 extension SKPaymentTransactionState {
-    
+
     var stringValue: String {
         switch self {
         case .purchasing: return "purchasing"
@@ -52,33 +52,32 @@ extension SKPaymentTransactionState {
 class CompleteTransactionsController: TransactionController {
 
     var completeTransactions: CompleteTransactions?
-    
+
     func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {
-        
+
         guard let completeTransactions = completeTransactions else {
             return transactions
         }
 
         var unhandledTransactions: [SKPaymentTransaction] = []
         var products: [Product] = []
-        
+
         for transaction in transactions {
-            
+
             let transactionState = transaction.transactionState
-            
+
             if transactionState != .purchasing {
-                
+
                 let product = Product(productId: transaction.payment.productIdentifier, transaction: transaction, needsFinishTransaction: !completeTransactions.atomically)
-                
+
                 products.append(product)
-                
+
                 print("Finishing transaction for payment \"\(transaction.payment.productIdentifier)\" with state: \(transactionState.stringValue)")
-                
+
                 if completeTransactions.atomically {
                     paymentQueue.finishTransaction(transaction)
                 }
-            }
-            else {
+            } else {
                 unhandledTransactions.append(transaction)
             }
         }

+ 8 - 8
SwiftyStoreKit/InAppProductQueryRequest.swift

@@ -34,13 +34,13 @@ class InAppProductQueryRequest: NSObject, SKProductsRequestDelegate {
         request.delegate = nil
     }
     private init(productIds: Set<String>, callback: @escaping RequestCallback) {
-        
+
         self.callback = callback
         request = SKProductsRequest(productIdentifiers: productIds)
         super.init()
         request.delegate = self
     }
-    
+
     class func startQuery(_ productIds: Set<String>, callback: @escaping RequestCallback) -> InAppProductQueryRequest {
         let request = InAppProductQueryRequest(productIds: productIds, callback: callback)
         request.start()
@@ -53,28 +53,28 @@ class InAppProductQueryRequest: NSObject, SKProductsRequestDelegate {
     func cancel() {
         self.request.cancel()
     }
-    
+
     // MARK: SKProductsRequestDelegate
     func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
-        
+
         DispatchQueue.main.async {
-            
+
             let retrievedProducts = Set<SKProduct>(response.products)
             let invalidProductIDs = Set<String>(response.invalidProductIdentifiers)
             self.callback(RetrieveResults(retrievedProducts: retrievedProducts,
                 invalidProductIDs: invalidProductIDs, error: nil))
         }
     }
-    
+
     func requestDidFinish(_ request: SKRequest) {
-        
+
     }
 
     func request(_ request: SKRequest, didFailWithError error: Error) {
         requestFailed(error)
     }
 
-    func requestFailed(_ error: Error){
+    func requestFailed(_ error: Error) {
         DispatchQueue.main.async {
             self.callback(RetrieveResults(retrievedProducts: Set<SKProduct>(), invalidProductIDs: Set<String>(), error: error))
         }

+ 16 - 17
SwiftyStoreKit/InAppReceipt.swift

@@ -65,7 +65,7 @@ internal class InAppReceipt {
 
 			validator.validate(receipt: base64EncodedString, password: autoRenewPassword, completion: completion)
     }
-  
+
     /**
      *  Verify the purchase of a Consumable or NonConsumable product in a receipt
      *  - Parameter productId: the product id of the purchase to verify
@@ -76,15 +76,15 @@ internal class InAppReceipt {
         productId: String,
         inReceipt receipt: ReceiptInfo
     ) -> VerifyPurchaseResult {
-      
+
         // Get receipts info for the product
         let receipts = receipt["receipt"]?["in_app"] as? [ReceiptInfo]
         let receiptsInfo = filterReceiptsInfo(receipts: receipts, withProductId: productId)
-      
+
         // Verify that at least one receipt has the right product id
         return receiptsInfo.count >= 1 ? .purchased : .notPurchased
     }
-  
+
     /**
      *  Verify the purchase of a subscription (auto-renewable, free or non-renewing) in a receipt. This method extracts all transactions mathing the given productId and sorts them by date in descending order, then compares the first transaction expiry date against the validUntil value.
      *  - Parameter productId: the product id of the purchase to verify
@@ -99,7 +99,7 @@ internal class InAppReceipt {
         validUntil date: Date = Date(),
         validDuration duration: TimeInterval? = nil
     ) -> VerifySubscriptionResult {
-      
+
         // Verify that at least one receipt has the right product id
 
         // The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt.
@@ -108,9 +108,9 @@ internal class InAppReceipt {
         if receiptsInfo.count == 0 {
             return .notPurchased
         }
-    
+
         let receiptDate = getReceiptRequestDate(inReceipt: receipt) ?? date
-        
+
         // Return the expires dates sorted desc
         let expiryDateValues = receiptsInfo
             .flatMap { (receipt) -> String? in
@@ -128,25 +128,24 @@ internal class InAppReceipt {
                 // Sort by descending date order
                 return a.compare(b) == .orderedDescending
             }
-      
+
         guard let firstExpiryDate = expiryDateValues.first else {
             return .notPurchased
         }
-        
+
         // Check if at least 1 receipt is valid
         if firstExpiryDate.compare(receiptDate) == .orderedDescending {
-            
+
             // The subscription is valid
             return .purchased(expiryDate: firstExpiryDate)
-        }
-        else {
+        } else {
             // The subscription is expired
             return .expired(expiryDate: firstExpiryDate)
         }
     }
-  
+
     private class func getReceiptRequestDate(inReceipt receipt: ReceiptInfo) -> Date? {
-        
+
         guard let receiptInfo = receipt["receipt"] as? ReceiptInfo,
             let requestDateString = receiptInfo["request_date_ms"] as? String,
             let requestDateMs = Double(requestDateString) else {
@@ -154,7 +153,7 @@ internal class InAppReceipt {
         }
         return Date(timeIntervalSince1970: requestDateMs / 1000)
     }
-    
+
     /**
      *  Get all the receipts info for a specific product
      *  - Parameter receipts: the receipts array to grab info from
@@ -165,14 +164,14 @@ internal class InAppReceipt {
         guard let receipts = receipts else {
             return []
         }
-      
+
         // Filter receipts with matching product id
         let receiptsMatchingProductId = receipts
             .filter { (receipt) -> Bool in
                 let product_id = receipt["product_id"] as? String
                 return product_id == productId
             }
-      
+
         return receiptsMatchingProductId
     }
 }

+ 9 - 9
SwiftyStoreKit/InAppReceiptRefreshRequest.swift

@@ -27,38 +27,38 @@ import StoreKit
 import Foundation
 
 class InAppReceiptRefreshRequest: NSObject, SKRequestDelegate {
-    
+
     enum ResultType {
         case success
         case error(e: Error)
     }
-    
+
     typealias RequestCallback = (ResultType) -> ()
-    
+
     class func refresh(_ receiptProperties: [String : Any]? = nil, callback: @escaping RequestCallback) -> InAppReceiptRefreshRequest {
         let request = InAppReceiptRefreshRequest(receiptProperties: receiptProperties, callback: callback)
         request.start()
         return request
     }
-    
+
     let refreshReceiptRequest: SKReceiptRefreshRequest
     let callback: RequestCallback
-    
+
     deinit {
         refreshReceiptRequest.delegate = nil
     }
-    
+
     private init(receiptProperties: [String : Any]? = nil, callback: @escaping RequestCallback) {
         self.callback = callback
         self.refreshReceiptRequest = SKReceiptRefreshRequest(receiptProperties: receiptProperties)
         super.init()
         self.refreshReceiptRequest.delegate = self
     }
-    
+
     func start() {
         self.refreshReceiptRequest.start()
     }
-    
+
     func requestDidFinish(_ request: SKRequest) {
         /*if let resoreRequest = request as? SKReceiptRefreshRequest {
          let receiptProperties = resoreRequest.receiptProperties ?? [:]
@@ -72,5 +72,5 @@ class InAppReceiptRefreshRequest: NSObject, SKRequestDelegate {
         // XXX could here check domain and error code to return typed exception
         callback(.error(e: error))
     }
-    
+
 }

+ 31 - 31
SwiftyStoreKit/PaymentQueueController.swift

@@ -26,7 +26,7 @@ import Foundation
 import StoreKit
 
 protocol TransactionController {
-    
+
     /**
      * - param transactions: transactions to process
      * - param paymentQueue: payment queue for finishing transactions
@@ -47,22 +47,22 @@ public protocol PaymentQueue: class {
     func remove(_ observer: SKPaymentTransactionObserver)
 
     func add(_ payment: SKPayment)
-    
+
     func restoreCompletedTransactions(withApplicationUsername username: String?)
-    
+
     func finishTransaction(_ transaction: SKPaymentTransaction)
 }
 
 extension SKPaymentQueue: PaymentQueue { }
 
 class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
-    
+
     private let paymentsController: PaymentsController
-    
+
     private let restorePurchasesController: RestorePurchasesController
-    
+
     private let completeTransactionsController: CompleteTransactionsController
-    
+
     unowned let paymentQueue: PaymentQueue
 
     deinit {
@@ -73,7 +73,7 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
                 paymentsController: PaymentsController = PaymentsController(),
                 restorePurchasesController: RestorePurchasesController = RestorePurchasesController(),
                 completeTransactionsController: CompleteTransactionsController = CompleteTransactionsController()) {
-     
+
         self.paymentQueue = paymentQueue
         self.paymentsController = paymentsController
         self.restorePurchasesController = restorePurchasesController
@@ -81,33 +81,33 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
         super.init()
         paymentQueue.add(self)
     }
-    
+
     func startPayment(_ payment: Payment) {
-        
+
         let skPayment = SKMutablePayment(product: payment.product)
         skPayment.applicationUsername = payment.applicationUsername
         paymentQueue.add(skPayment)
-        
+
         paymentsController.append(payment)
     }
-    
+
     func restorePurchases(_ restorePurchases: RestorePurchases) {
-        
+
         if restorePurchasesController.restorePurchases != nil {
             // return .inProgress
             return
         }
-        
+
         paymentQueue.restoreCompletedTransactions(withApplicationUsername: restorePurchases.applicationUsername)
-        
+
         restorePurchasesController.restorePurchases = restorePurchases
     }
-    
+
     func completeTransactions(_ completeTransactions: CompleteTransactions) {
-        
+
         completeTransactionsController.completeTransactions = completeTransactions
     }
-    
+
     func finishTransaction(_ transaction: PaymentTransaction) {
         guard let skTransaction = transaction as? SKPaymentTransaction else {
             print("Object is not a SKPaymentTransaction: \(transaction)")
@@ -116,10 +116,10 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
         paymentQueue.finishTransaction(skTransaction)
     }
 
-    
+
     // MARK: SKPaymentTransactionObserver
     func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
-        
+
         /*
          * Some notes about how requests are processed by SKPaymentQueue:
          *
@@ -134,7 +134,7 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
          * A complete transactions handler is require to catch any transactions that are updated when the app is not running.
          * Registering a complete transactions handler when the app launches ensures that any pending transactions can be cleared.
          * If a complete transactions handler is missing, pending transactions can be mis-attributed to any new incoming payments or restore purchases.
-         * 
+         *
          * The order in which transaction updates are processed is:
          * 1. payments (transactionState: .purchased and .failed for matching product identifiers)
          * 2. restore purchases (transactionState: .restored, or restoreCompletedTransactionsFailedWithError, or paymentQueueRestoreCompletedTransactionsFinished)
@@ -142,32 +142,32 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
          * Any transactions where state == .purchasing are ignored.
          */
         var unhandledTransactions = paymentsController.processTransactions(transactions, on: paymentQueue)
-        
+
         unhandledTransactions = restorePurchasesController.processTransactions(unhandledTransactions, on: paymentQueue)
-        
+
         unhandledTransactions = completeTransactionsController.processTransactions(unhandledTransactions, on: paymentQueue)
-        
+
         if unhandledTransactions.count > 0 {
             print("unhandledTransactions: \(unhandledTransactions)")
         }
     }
-    
+
     func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
-        
+
     }
-    
+
     func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
-        
+
         restorePurchasesController.restoreCompletedTransactionsFailed(withError: error)
     }
-    
+
     func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
 
         restorePurchasesController.restoreCompletedTransactionsFinished()
     }
-    
+
     func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) {
-        
+
     }
 
 }

+ 18 - 19
SwiftyStoreKit/PaymentsController.swift

@@ -31,19 +31,19 @@ struct Payment: Hashable {
     let atomically: Bool
     let applicationUsername: String
     let callback: (TransactionResult) -> ()
-    
+
     var hashValue: Int {
         return product.productIdentifier.hashValue
     }
-    static func ==(lhs: Payment, rhs: Payment) -> Bool {
+    static func == (lhs: Payment, rhs: Payment) -> Bool {
         return lhs.product.productIdentifier == rhs.product.productIdentifier
     }
 }
 
 class PaymentsController: TransactionController {
-    
+
     private var payments: [Payment] = []
-    
+
     private func findPaymentIndex(withProductIdentifier identifier: String) -> Int? {
         for payment in payments {
             if payment.product.productIdentifier == identifier {
@@ -52,33 +52,33 @@ class PaymentsController: TransactionController {
         }
         return nil
     }
-    
+
     func hasPayment(_ payment: Payment) -> Bool {
         return findPaymentIndex(withProductIdentifier: payment.product.productIdentifier) != nil
     }
-    
+
     func append(_ payment: Payment) {
         payments.append(payment)
     }
-    
+
     func processTransaction(_ transaction: SKPaymentTransaction, on paymentQueue: PaymentQueue) -> Bool {
-        
+
         let transactionProductIdentifier = transaction.payment.productIdentifier
-        
+
         guard let paymentIndex = findPaymentIndex(withProductIdentifier: transactionProductIdentifier) else {
 
             return false
         }
         let payment = payments[paymentIndex]
-        
+
         let transactionState = transaction.transactionState
-        
+
         if transactionState == .purchased {
 
             let product = Product(productId: transactionProductIdentifier, transaction: transaction, needsFinishTransaction: !payment.atomically)
-            
+
             payment.callback(.purchased(product: product))
-            
+
             if payment.atomically {
                 paymentQueue.finishTransaction(transaction)
             }
@@ -88,28 +88,27 @@ class PaymentsController: TransactionController {
         if transactionState == .failed {
 
             payment.callback(.failed(error: transactionError(for: transaction.error as NSError?)))
-            
+
             paymentQueue.finishTransaction(transaction)
             payments.remove(at: paymentIndex)
             return true
         }
-        
+
         if transactionState == .restored {
             print("Unexpected restored transaction for payment \(transactionProductIdentifier)")
         }
         return false
     }
-    
+
     func transactionError(for error: NSError?) -> SKError {
         let message = "Unknown error"
         let altError = NSError(domain: SKErrorDomain, code: SKError.unknown.rawValue, userInfo: [ NSLocalizedDescriptionKey: message ])
         let nsError = error ?? altError
         return SKError(_nsError: nsError)
     }
-        
+
     func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {
-        
+
         return transactions.filter { !processTransaction($0, on: paymentQueue) }
     }
 }
-

+ 8 - 8
SwiftyStoreKit/ProductsInfoController.swift

@@ -37,16 +37,16 @@ class ProductsInfoController: NSObject {
     private func addProduct(_ product: SKProduct) {
         products[product.productIdentifier] = product
     }
-    
+
     private func allProductsMatching(_ productIds: Set<String>) -> Set<SKProduct> {
-        
+
         return Set(productIds.flatMap { self.products[$0] })
     }
-    
+
     private func requestProducts(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> ()) {
-        
+
         inflightQueries[productIds] = InAppProductQueryRequest.startQuery(productIds) { result in
-            
+
             self.inflightQueries[productIds] = nil
             for product in result.retrievedProducts {
                 self.addProduct(product)
@@ -54,12 +54,12 @@ class ProductsInfoController: NSObject {
             completion(result)
         }
     }
-    
+
     func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> ()) {
-        
+
         let products = allProductsMatching(productIds)
         guard products.count == productIds.count else {
-            
+
             requestProducts(productIds, completion: completion)
             return
         }

+ 18 - 19
SwiftyStoreKit/RestorePurchasesController.swift

@@ -29,7 +29,7 @@ struct RestorePurchases {
     let atomically: Bool
     let applicationUsername: String?
     let callback: ([TransactionResult]) -> ()
-    
+
     init(atomically: Bool, applicationUsername: String? = nil, callback: @escaping ([TransactionResult]) -> ()) {
         self.atomically = atomically
         self.applicationUsername = applicationUsername
@@ -38,19 +38,19 @@ struct RestorePurchases {
 }
 
 class RestorePurchasesController: TransactionController {
-    
+
     public var restorePurchases: RestorePurchases?
-    
+
     private var restoredProducts: [TransactionResult] = []
-    
+
     func processTransaction(_ transaction: SKPaymentTransaction, atomically: Bool, on paymentQueue: PaymentQueue) -> Product? {
-        
+
         let transactionState = transaction.transactionState
-        
+
         if transactionState == .restored {
-            
+
             let transactionProductIdentifier = transaction.payment.productIdentifier
-            
+
             let product = Product(productId: transactionProductIdentifier, transaction: transaction, needsFinishTransaction: !atomically)
             if atomically {
                 paymentQueue.finishTransaction(transaction)
@@ -59,47 +59,46 @@ class RestorePurchasesController: TransactionController {
         }
         return nil
     }
-    
+
     func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {
-        
+
         guard let restorePurchases = restorePurchases else {
             return transactions
         }
-        
+
         var unhandledTransactions: [SKPaymentTransaction] = []
         for transaction in transactions {
             if let restoredProduct = processTransaction(transaction, atomically: restorePurchases.atomically, on: paymentQueue) {
                 restoredProducts.append(.restored(product: restoredProduct))
-            }
-            else {
+            } else {
                 unhandledTransactions.append(transaction)
             }
         }
 
         return unhandledTransactions
     }
-    
+
     func restoreCompletedTransactionsFailed(withError error: Error) {
-        
+
         guard let restorePurchases = restorePurchases else {
             return
         }
         restoredProducts.append(.failed(error: SKError(_nsError: error as NSError)))
         restorePurchases.callback(restoredProducts)
-        
+
         // Reset state after error received
         restoredProducts = []
         self.restorePurchases = nil
 
     }
-    
+
     func restoreCompletedTransactionsFinished() {
-        
+
         guard let restorePurchases = restorePurchases else {
             return
         }
         restorePurchases.callback(restoredProducts)
-        
+
         // Reset state after error transactions finished
         restoredProducts = []
         self.restorePurchases = nil

+ 3 - 3
SwiftyStoreKit/SwiftyStoreKit+Types.swift

@@ -137,7 +137,7 @@ public enum ReceiptStatus: Int {
     case testReceipt = 21007
     // This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.
     case productionEnvironment = 21008
-    
+
     var isValid: Bool { return self == .valid}
 }
 
@@ -153,10 +153,10 @@ public enum ReceiptInfoField: String {
     case creation_date
     // The date that the app receipt expires. This key is present only for apps purchased through the Volume Purchase Program.
     case expiration_date
-    
+
     // The receipt for an in-app purchase.
     case in_app
-    
+
     public enum InApp: String {
         // The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property.
         case quantity

+ 42 - 46
SwiftyStoreKit/SwiftyStoreKit.swift

@@ -29,36 +29,33 @@ public class SwiftyStoreKit {
     private let productsInfoController: ProductsInfoController
 
     private let paymentQueueController: PaymentQueueController
-    
+
     private var receiptRefreshRequest: InAppReceiptRefreshRequest?
-    
+
     init(productsInfoController: ProductsInfoController = ProductsInfoController(),
          paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default())) {
-        
+
         self.productsInfoController = productsInfoController
         self.paymentQueueController = paymentQueueController
     }
 
     // MARK: Internal methods
-    
+
     func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> ()) {
         return productsInfoController.retrieveProductsInfo(productIds, completion: completion)
     }
-    
+
     func purchaseProduct(_ productId: String, atomically: Bool = true, applicationUsername: String = "", completion: @escaping ( PurchaseResult) -> ()) {
-        
+
         if let product = productsInfoController.products[productId] {
             purchase(product: product, atomically: atomically, applicationUsername: applicationUsername, completion: completion)
-        }
-        else {
+        } else {
             retrieveProductsInfo(Set([productId])) { result -> () in
                 if let product = result.retrievedProducts.first {
                     self.purchase(product: product, atomically: atomically, applicationUsername: applicationUsername, completion: completion)
-                }
-                else if let error = result.error {
+                } else if let error = result.error {
                     completion(.error(error: SKError(_nsError: error as NSError)))
-                }
-                else if let invalidProductId = result.invalidProductIDs.first {
+                } else if let invalidProductId = result.invalidProductIDs.first {
                     let userInfo = [ NSLocalizedDescriptionKey: "Invalid product id: \(invalidProductId)" ]
                     let error = NSError(domain: SKErrorDomain, code: SKError.paymentInvalid.rawValue, userInfo: userInfo)
                     completion(.error(error: SKError(_nsError: error)))
@@ -66,37 +63,36 @@ public class SwiftyStoreKit {
             }
         }
     }
-    
+
     func restorePurchases(atomically: Bool = true, applicationUsername: String = "", completion: @escaping (RestoreResults) -> ()) {
-        
+
         paymentQueueController.restorePurchases(RestorePurchases(atomically: atomically, applicationUsername: applicationUsername) { results in
-            
+
             let results = self.processRestoreResults(results)
             completion(results)
         })
     }
-    
+
     func completeTransactions(atomically: Bool = true, completion: @escaping ([Product]) -> ()) {
-        
+
         paymentQueueController.completeTransactions(CompleteTransactions(atomically: atomically, callback: completion))
     }
-    
+
     func finishTransaction(_ transaction: PaymentTransaction) {
-        
+
         paymentQueueController.finishTransaction(transaction)
     }
 
     func refreshReceipt(_ receiptProperties: [String : Any]? = nil, completion: @escaping (RefreshReceiptResult) -> ()) {
         receiptRefreshRequest = InAppReceiptRefreshRequest.refresh(receiptProperties) { result in
-            
+
             self.receiptRefreshRequest = nil
-            
+
             switch result {
             case .success:
                 if let appStoreReceiptData = InAppReceipt.appStoreReceiptData {
                     completion(.success(receiptData: appStoreReceiptData))
-                }
-                else {
+                } else {
                     completion(.error(error: ReceiptError.noReceiptData))
                 }
             case .error(let e):
@@ -112,9 +108,9 @@ public class SwiftyStoreKit {
             completion(.error(error: SKError(_nsError: error)))
             return
         }
-        
+
         paymentQueueController.startPayment(Payment(product: product, atomically: atomically, applicationUsername: applicationUsername) { result in
-            
+
             completion(self.processPurchaseResult(result))
         })
     }
@@ -129,7 +125,7 @@ public class SwiftyStoreKit {
             return .error(error: storeInternalError(description: "Cannot restore product \(product.productId) from purchase path"))
         }
     }
-    
+
     private func processRestoreResults(_ results: [TransactionResult]) -> RestoreResults {
         var restoredProducts: [Product] = []
         var restoreFailedProducts: [(SKError, String?)] = []
@@ -146,7 +142,7 @@ public class SwiftyStoreKit {
         }
         return RestoreResults(restoredProducts: restoredProducts, restoreFailedProducts: restoreFailedProducts)
     }
-    
+
     private func storeInternalError(code: SKError.Code = SKError.unknown, description: String = "") -> SKError {
         let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ])
         return SKError(_nsError: error)
@@ -157,17 +153,17 @@ extension SwiftyStoreKit {
 
     // MARK: Singleton
     private static let sharedInstance = SwiftyStoreKit()
-    
+
     // MARK: Public methods - Purchases
     public class var canMakePayments: Bool {
         return SKPaymentQueue.canMakePayments()
     }
 
     public class func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> ()) {
-        
+
         return sharedInstance.retrieveProductsInfo(productIds, completion: completion)
     }
-    
+
     /**
      *  Purchase a product
      *  - Parameter productId: productId as specified in iTunes Connect
@@ -176,44 +172,44 @@ extension SwiftyStoreKit {
      *  - Parameter completion: handler for result
      */
     public class func purchaseProduct(_ productId: String, atomically: Bool = true, applicationUsername: String = "", completion: @escaping ( PurchaseResult) -> ()) {
-        
+
         sharedInstance.purchaseProduct(productId, atomically: atomically, applicationUsername: applicationUsername, completion: completion)
     }
-    
+
     public class func restorePurchases(atomically: Bool = true, applicationUsername: String = "", completion: @escaping (RestoreResults) -> ()) {
-        
+
         sharedInstance.restorePurchases(atomically: atomically, applicationUsername: applicationUsername, completion: completion)
     }
-    
+
     public class func completeTransactions(atomically: Bool = true, completion: @escaping ([Product]) -> ()) {
-        
+
         sharedInstance.completeTransactions(atomically: atomically, completion: completion)
     }
-    
-    
+
+
     public class func finishTransaction(_ transaction: PaymentTransaction) {
-        
+
         sharedInstance.finishTransaction(transaction)
     }
 
     // After verifying receive and have `ReceiptError.NoReceiptData`, refresh receipt using this method
     public class func refreshReceipt(_ receiptProperties: [String : Any]? = nil, completion: @escaping (RefreshReceiptResult) -> ()) {
-        
+
         sharedInstance.refreshReceipt(receiptProperties, completion: completion)
     }
 }
 
 extension SwiftyStoreKit {
- 
+
     // MARK: Public methods - Receipt verification
-    
+
     /**
      * Return receipt data from the application bundle. This is read from Bundle.main.appStoreReceiptURL
      */
     public static var localReceiptData: Data? {
         return InAppReceipt.appStoreReceiptData
     }
-    
+
     /**
      *  Verify application receipt
      *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
@@ -224,15 +220,15 @@ extension SwiftyStoreKit {
         using validator: ReceiptValidator,
         password: String? = nil,
         completion:@escaping (VerifyReceiptResult) -> ()) {
-        
+
         InAppReceipt.verify(using: validator, password: password) { result in
-            
+
             DispatchQueue.main.async {
                 completion(result)
             }
         }
     }
-    
+
     /**
      *  Verify the purchase of a Consumable or NonConsumable product in a receipt
      *  - Parameter productId: the product id of the purchase to verify
@@ -245,7 +241,7 @@ extension SwiftyStoreKit {
         ) -> VerifyPurchaseResult {
         return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt)
     }
-    
+
     /**
      *  Verify the purchase of a subscription (auto-renewable, free or non-renewing) in a receipt. This method extracts all transactions mathing the given productId and sorts them by date in descending order, then compares the first transaction expiry date against the validUntil value.
      *  - Parameter productId: the product id of the purchase to verify

+ 24 - 24
SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift

@@ -29,12 +29,12 @@ import StoreKit
 class CompleteTransactionsControllerTests: XCTestCase {
 
     func testProcessTransactions_when_oneRestoredTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions() {
-        
+
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct = TestProduct(productIdentifier: productIdentifier)
-        
+
         let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .restored)
-        
+
         var callbackCalled = false
         let restorePurchases = CompleteTransactions(atomically: true) { products in
             callbackCalled = true
@@ -42,22 +42,22 @@ class CompleteTransactionsControllerTests: XCTestCase {
             let product = products.first!
             XCTAssertEqual(product.productId, productIdentifier)
         }
-        
+
         let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: restorePurchases)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = completeTransactionsController.processTransactions([transaction], on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
-        
+
         XCTAssertTrue(callbackCalled)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 1)
     }
-    
+
     func testProcessTransactions_when_oneTransactionForEachState_then_finishesTransactions_callsCallback_onePurchasingTransactionRemaining() {
-        
+
         let transactions = [
             makeTestPaymentTransaction(productIdentifier: "com.SwiftyStoreKit.product1", transactionState: .purchased),
             makeTestPaymentTransaction(productIdentifier: "com.SwiftyStoreKit.product2", transactionState: .failed),
@@ -65,7 +65,7 @@ class CompleteTransactionsControllerTests: XCTestCase {
             makeTestPaymentTransaction(productIdentifier: "com.SwiftyStoreKit.product4", transactionState: .deferred),
             makeTestPaymentTransaction(productIdentifier: "com.SwiftyStoreKit.product5", transactionState: .purchasing),
         ]
-        
+
         var callbackCalled = false
         let restorePurchases = CompleteTransactions(atomically: true) { products in
             callbackCalled = true
@@ -75,32 +75,32 @@ class CompleteTransactionsControllerTests: XCTestCase {
                 XCTAssertEqual(products[i].productId, transactions[i].payment.productIdentifier)
             }
         }
-        
+
         let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: restorePurchases)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = completeTransactionsController.processTransactions(transactions, on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 1)
-        
+
         XCTAssertTrue(callbackCalled)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 4)
     }
-    
+
     func makeTestPaymentTransaction(productIdentifier: String, transactionState: SKPaymentTransactionState) -> TestPaymentTransaction {
-        
+
         let testProduct = TestProduct(productIdentifier: productIdentifier)
         return TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: transactionState)
     }
-    
+
     func makeCompleteTransactionsController(completeTransactions: CompleteTransactions?) -> CompleteTransactionsController {
-        
+
         let completeTransactionsController = CompleteTransactionsController()
-        
+
         completeTransactionsController.completeTransactions = completeTransactions
-        
+
         return completeTransactionsController
     }
 

+ 51 - 55
SwiftyStoreKitTests/PaymentQueueControllerTests.swift

@@ -39,44 +39,44 @@ class PaymentQueueControllerTests: XCTestCase {
 
     // MARK: init/deinit
     func testInit_registersAsObserver() {
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let paymentQueueController = PaymentQueueController(paymentQueue: spy)
-        
+
         XCTAssertTrue(spy.observer === paymentQueueController)
     }
-    
+
     func testDeinit_removesObserver() {
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let _ = PaymentQueueController(paymentQueue: spy)
-        
+
         XCTAssertNil(spy.observer)
     }
-    
+
     // MARK: Start payment
-    
+
     func testStartTransaction_QueuesOnePayment() {
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let paymentQueueController = PaymentQueueController(paymentQueue: spy)
 
         let payment = makeTestPayment(productIdentifier: "com.SwiftyStoreKit.product1") { result in }
 
         paymentQueueController.startPayment(payment)
-        
+
         XCTAssertEqual(spy.payments.count, 1)
     }
-    
+
     // MARK: SKPaymentTransactionObserver callbacks
     func testPaymentQueue_when_oneTransactionForEachState_onePayment_oneRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {
 
         // setup
         let spy = PaymentQueueSpy()
-        
+
         let paymentQueueController = PaymentQueueController(paymentQueue: spy)
 
         let purchasedProductIdentifier = "com.SwiftyStoreKit.product1"
@@ -84,7 +84,7 @@ class PaymentQueueControllerTests: XCTestCase {
         let restoredProductIdentifier = "com.SwiftyStoreKit.product3"
         let deferredProductIdentifier = "com.SwiftyStoreKit.product4"
         let purchasingProductIdentifier = "com.SwiftyStoreKit.product5"
-        
+
         let transactions = [
             makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),
             makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),
@@ -93,14 +93,13 @@ class PaymentQueueControllerTests: XCTestCase {
             makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing),
             ]
 
-        
+
         var paymentCallbackCalled = false
         let testPayment = makeTestPayment(productIdentifier: purchasedProductIdentifier) { result in
             paymentCallbackCalled = true
             if case .purchased(let product) = result {
                 XCTAssertEqual(product.productId, purchasedProductIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected purchased callback with product id")
             }
         }
@@ -112,12 +111,11 @@ class PaymentQueueControllerTests: XCTestCase {
             let first = results.first!
             if case .restored(let restoredProduct) = first {
                 XCTAssertEqual(restoredProduct.productId, restoredProductIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected restored callback with product")
             }
         }
-        
+
         var completeTransactionsCallbackCalled = false
         let completeTransactions = CompleteTransactions(atomically: true) { products in
             completeTransactionsCallbackCalled = true
@@ -125,36 +123,36 @@ class PaymentQueueControllerTests: XCTestCase {
             XCTAssertEqual(products[0].productId, failedProductIdentifier)
             XCTAssertEqual(products[1].productId, deferredProductIdentifier)
         }
-        
+
         // run
         paymentQueueController.startPayment(testPayment)
-        
+
         paymentQueueController.restorePurchases(restorePurchases)
 
         paymentQueueController.completeTransactions(completeTransactions)
-        
+
         paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)
         paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())
-        
+
         // verify
         XCTAssertTrue(paymentCallbackCalled)
         XCTAssertTrue(restorePurchasesCallbackCalled)
         XCTAssertTrue(completeTransactionsCallbackCalled)
     }
-    
+
     func testPaymentQueue_when_oneTransactionForEachState_onePayment_noRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {
-        
+
         // setup
         let spy = PaymentQueueSpy()
-        
+
         let paymentQueueController = PaymentQueueController(paymentQueue: spy)
-        
+
         let purchasedProductIdentifier = "com.SwiftyStoreKit.product1"
         let failedProductIdentifier = "com.SwiftyStoreKit.product2"
         let restoredProductIdentifier = "com.SwiftyStoreKit.product3"
         let deferredProductIdentifier = "com.SwiftyStoreKit.product4"
         let purchasingProductIdentifier = "com.SwiftyStoreKit.product5"
-        
+
         let transactions = [
             makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),
             makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),
@@ -162,19 +160,18 @@ class PaymentQueueControllerTests: XCTestCase {
             makeTestPaymentTransaction(productIdentifier: deferredProductIdentifier, transactionState: .deferred),
             makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing),
             ]
-        
-        
+
+
         var paymentCallbackCalled = false
         let testPayment = makeTestPayment(productIdentifier: purchasedProductIdentifier) { result in
             paymentCallbackCalled = true
             if case .purchased(let product) = result {
                 XCTAssertEqual(product.productId, purchasedProductIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected purchased callback with product id")
             }
         }
-        
+
         var completeTransactionsCallbackCalled = false
         let completeTransactions = CompleteTransactions(atomically: true) { products in
             completeTransactionsCallbackCalled = true
@@ -183,33 +180,33 @@ class PaymentQueueControllerTests: XCTestCase {
             XCTAssertEqual(products[1].productId, restoredProductIdentifier)
             XCTAssertEqual(products[2].productId, deferredProductIdentifier)
         }
-        
+
         // run
         paymentQueueController.startPayment(testPayment)
-        
+
         paymentQueueController.completeTransactions(completeTransactions)
-        
+
         paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)
         paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())
-        
+
         // verify
         XCTAssertTrue(paymentCallbackCalled)
         XCTAssertTrue(completeTransactionsCallbackCalled)
     }
 
     func testPaymentQueue_when_oneTransactionForEachState_noPayments_oneRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {
-        
+
         // setup
         let spy = PaymentQueueSpy()
-        
+
         let paymentQueueController = PaymentQueueController(paymentQueue: spy)
-        
+
         let purchasedProductIdentifier = "com.SwiftyStoreKit.product1"
         let failedProductIdentifier = "com.SwiftyStoreKit.product2"
         let restoredProductIdentifier = "com.SwiftyStoreKit.product3"
         let deferredProductIdentifier = "com.SwiftyStoreKit.product4"
         let purchasingProductIdentifier = "com.SwiftyStoreKit.product5"
-        
+
         let transactions = [
             makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),
             makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),
@@ -217,7 +214,7 @@ class PaymentQueueControllerTests: XCTestCase {
             makeTestPaymentTransaction(productIdentifier: deferredProductIdentifier, transactionState: .deferred),
             makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing),
             ]
-        
+
         var restorePurchasesCallbackCalled = false
         let restorePurchases = RestorePurchases(atomically: true) { results in
             restorePurchasesCallbackCalled = true
@@ -225,12 +222,11 @@ class PaymentQueueControllerTests: XCTestCase {
             let first = results.first!
             if case .restored(let restoredProduct) = first {
                 XCTAssertEqual(restoredProduct.productId, restoredProductIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected restored callback with product")
             }
         }
-        
+
         var completeTransactionsCallbackCalled = false
         let completeTransactions = CompleteTransactions(atomically: true) { products in
             completeTransactionsCallbackCalled = true
@@ -239,29 +235,29 @@ class PaymentQueueControllerTests: XCTestCase {
             XCTAssertEqual(products[1].productId, failedProductIdentifier)
             XCTAssertEqual(products[2].productId, deferredProductIdentifier)
         }
-        
+
         // run
         paymentQueueController.restorePurchases(restorePurchases)
-        
+
         paymentQueueController.completeTransactions(completeTransactions)
-        
+
         paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)
         paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())
-        
+
         // verify
         XCTAssertTrue(restorePurchasesCallbackCalled)
         XCTAssertTrue(completeTransactionsCallbackCalled)
     }
-    
+
     // MARK: Helpers
     func makeTestPaymentTransaction(productIdentifier: String, transactionState: SKPaymentTransactionState) -> TestPaymentTransaction {
-        
+
         let testProduct = TestProduct(productIdentifier: productIdentifier)
         return TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: transactionState)
     }
-    
+
     func makeTestPayment(productIdentifier: String, atomically: Bool = true, callback: @escaping (TransactionResult) -> ()) -> Payment {
-        
+
         let testProduct = TestProduct(productIdentifier: productIdentifier)
         return Payment(product: testProduct, atomically: atomically, applicationUsername: "", callback: callback)
     }

+ 11 - 11
SwiftyStoreKitTests/PaymentQueueSpy.swift

@@ -10,38 +10,38 @@ import SwiftyStoreKit
 import StoreKit
 
 class PaymentQueueSpy: PaymentQueue {
-    
+
     weak var observer: SKPaymentTransactionObserver?
-    
+
     var payments: [SKPayment] = []
-    
+
     var restoreCompletedTransactionCalledCount = 0
-    
+
     var finishTransactionCalledCount = 0
 
     func add(_ observer: SKPaymentTransactionObserver) {
-        
+
         self.observer = observer
     }
     func remove(_ observer: SKPaymentTransactionObserver) {
-        
+
         if self.observer === observer {
             self.observer = nil
         }
     }
-    
+
     func add(_ payment: SKPayment) {
-        
+
         payments.append(payment)
     }
-    
+
     func restoreCompletedTransactions(withApplicationUsername username: String?) {
-        
+
         restoreCompletedTransactionCalledCount += 1
     }
 
     func finishTransaction(_ transaction: SKPaymentTransaction) {
-        
+
         finishTransactionCalledCount += 1
     }
 }

+ 62 - 67
SwiftyStoreKitTests/PaymentsControllerTests.swift

@@ -29,95 +29,92 @@ import StoreKit
 class PaymentsControllerTests: XCTestCase {
 
     func testInsertPayment_hasPayment() {
-     
+
         let payment = makeTestPayment(productIdentifier: "com.SwiftyStoreKit.product1") { result in }
 
         let paymentsController = makePaymentsController(appendPayments: [payment])
-        
+
         XCTAssertTrue(paymentsController.hasPayment(payment))
     }
-    
+
     func testProcessTransaction_when_onePayment_transactionStatePurchased_then_removesPayment_finishesTransaction_callsCallback() {
-        
+
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct = TestProduct(productIdentifier: productIdentifier)
-        
+
         var callbackCalled = false
         let payment = makeTestPayment(product: testProduct) { result in
-            
+
             callbackCalled = true
             if case .purchased(let product) = result {
                 XCTAssertEqual(product.productId, productIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected purchased callback with product id")
             }
         }
-        
+
         let paymentsController = makePaymentsController(appendPayments: [payment])
-        
+
         let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .purchased)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = paymentsController.processTransactions([transaction], on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
 
         XCTAssertFalse(paymentsController.hasPayment(payment))
-        
+
         XCTAssertTrue(callbackCalled)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 1)
     }
-    
+
     func testProcessTransaction_when_onePayment_transactionStateFailed_then_removesPayment_finishesTransaction_callsCallback() {
-        
+
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct = TestProduct(productIdentifier: productIdentifier)
-        
+
         var callbackCalled = false
         let payment = makeTestPayment(product: testProduct) { result in
-            
+
             callbackCalled = true
             if case .failed(_) = result {
-                
-            }
-            else {
+
+            } else {
                 XCTFail("expected failed callback with error")
             }
         }
-        
+
         let paymentsController = makePaymentsController(appendPayments: [payment])
-        
+
         let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .failed)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = paymentsController.processTransactions([transaction], on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
-        
+
         XCTAssertFalse(paymentsController.hasPayment(payment))
-        
+
         XCTAssertTrue(callbackCalled)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 1)
     }
-    
+
     func testProcessTransaction_when_twoPaymentsSameId_firstTransactionStatePurchased_secondTransactionStateFailed_then_removesPayments_finishesTransactions_callsCallbacks() {
 
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct1 = TestProduct(productIdentifier: productIdentifier)
-        
+
         var callback1Called = false
         let payment1 = makeTestPayment(product: testProduct1) { result in
-            
+
             callback1Called = true
             if case .purchased(let product) = result {
                 XCTAssertEqual(product.productId, productIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected purchased callback with product id")
             }
         }
@@ -128,89 +125,87 @@ class PaymentsControllerTests: XCTestCase {
         let payment2 = makeTestPayment(product: testProduct2) { result in
             callback2Called = true
             if case .failed(_) = result {
-                
-            }
-            else {
+
+            } else {
                 XCTFail("expected failed callback with error")
             }
         }
 
         let paymentsController = makePaymentsController(appendPayments: [payment1, payment2])
-        
+
         let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .purchased)
         let transaction2 = TestPaymentTransaction(payment: SKPayment(product: testProduct2), transactionState: .failed)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = paymentsController.processTransactions([transaction1, transaction2], on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
-        
+
         XCTAssertFalse(paymentsController.hasPayment(payment1))
         XCTAssertFalse(paymentsController.hasPayment(payment2))
-        
+
         XCTAssertTrue(callback1Called)
         XCTAssertTrue(callback2Called)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 2)
     }
 
     func testProcessTransaction_when_twoPaymentsSameId_firstPayment_transactionStatePurchased_then_removesFirstPayment_finishesTransaction_callsCallback() {
-        
+
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct1 = TestProduct(productIdentifier: productIdentifier)
-        
+
         var callback1Called = false
         let payment1 = makeTestPayment(product: testProduct1) { result in
-            
+
             callback1Called = true
             if case .purchased(let product) = result {
                 XCTAssertEqual(product.productId, productIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected purchased callback with product id")
             }
         }
-        
+
         let testProduct2 = TestProduct(productIdentifier: productIdentifier)
         let payment2 = makeTestPayment(product: testProduct2) { result in
-            
+
             XCTFail("unexpected callback for second payment")
         }
-        
+
         let paymentsController = makePaymentsController(appendPayments: [payment1, payment2])
-        
+
         let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .purchased)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = paymentsController.processTransactions([transaction1], on: spy)
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
-        
+
         // First one removed, but second one with same identifier still there
         XCTAssertTrue(paymentsController.hasPayment(payment2))
-        
+
         XCTAssertTrue(callback1Called)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 1)
     }
 
-    
+
     func makePaymentsController(appendPayments payments: [Payment]) -> PaymentsController {
-        
+
         let paymentsController = PaymentsController()
-        
+
         payments.forEach { paymentsController.append($0) }
-        
+
         return paymentsController
     }
-    
+
     func makeTestPayment(product: SKProduct, atomically: Bool = true, callback: @escaping (TransactionResult) -> ()) -> Payment {
-        
+
         return Payment(product: product, atomically: atomically, applicationUsername: "", callback: callback)
     }
-    
+
     func makeTestPayment(productIdentifier: String, atomically: Bool = true, callback: @escaping (TransactionResult) -> ()) -> Payment {
 
         let product = TestProduct(productIdentifier: productIdentifier)

+ 27 - 31
SwiftyStoreKitTests/RestorePurchasesControllerTests.swift

@@ -28,12 +28,12 @@ import StoreKit
 @testable import SwiftyStoreKit
 
 class RestorePurchasesControllerTests: XCTestCase {
-    
+
     func testProcessTransactions_when_oneRestoredTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions() {
-        
+
         let productIdentifier = "com.SwiftyStoreKit.product1"
         let testProduct = TestProduct(productIdentifier: productIdentifier)
-        
+
         let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .restored)
 
         var callbackCalled = false
@@ -43,19 +43,18 @@ class RestorePurchasesControllerTests: XCTestCase {
             let restored = results.first!
             if case .restored(let restoredProduct) = restored {
                 XCTAssertEqual(restoredProduct.productId, productIdentifier)
-            }
-            else {
+            } else {
                 XCTFail("expected restored callback with product")
             }
         }
-        
+
         let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)
-        
+
         let spy = PaymentQueueSpy()
 
         let remainingTransactions = restorePurchasesController.processTransactions([transaction], on: spy)
         restorePurchasesController.restoreCompletedTransactionsFinished()
-        
+
         XCTAssertEqual(remainingTransactions.count, 0)
 
         XCTAssertTrue(callbackCalled)
@@ -64,7 +63,7 @@ class RestorePurchasesControllerTests: XCTestCase {
     }
 
     func testProcessTransactions_when_twoRestoredTransactions_oneFailedTransaction_onePurchasedTransaction_then_finishesTwoTransactions_callsCallback_twoRemainingTransaction() {
-        
+
         let productIdentifier1 = "com.SwiftyStoreKit.product1"
         let testProduct1 = TestProduct(productIdentifier: productIdentifier1)
         let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .restored)
@@ -90,33 +89,31 @@ class RestorePurchasesControllerTests: XCTestCase {
             let first = results.first!
             if case .restored(let restoredProduct) = first {
                 XCTAssertEqual(restoredProduct.productId, productIdentifier1)
-            }
-            else {
+            } else {
                 XCTFail("expected restored callback with product")
             }
             let last = results.last!
             if case .restored(let restoredProduct) = last {
                 XCTAssertEqual(restoredProduct.productId, productIdentifier2)
-            }
-            else {
+            } else {
                 XCTFail("expected restored callback with product")
             }
         }
-        
+
         let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)
-        
+
         let spy = PaymentQueueSpy()
-        
+
         let remainingTransactions = restorePurchasesController.processTransactions(transactions, on: spy)
         restorePurchasesController.restoreCompletedTransactionsFinished()
 
         XCTAssertEqual(remainingTransactions.count, 2)
-        
+
         XCTAssertTrue(callbackCalled)
-        
+
         XCTAssertEqual(spy.finishTransactionCalledCount, 2)
     }
-    
+
     func testRestoreCompletedTransactionsFailed_callsCallbackWithError() {
 
         var callbackCalled = false
@@ -126,24 +123,23 @@ class RestorePurchasesControllerTests: XCTestCase {
             XCTAssertEqual(results.count, 1)
             let first = results.first!
             if case .failed(_) = first {
-                
-            }
-            else {
+
+            } else {
                 XCTFail("expected failed callback with error")
             }
         }
-        
+
         let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)
 
         let error = NSError(domain: "SwiftyStoreKit", code: 0, userInfo: nil)
-        
+
         restorePurchasesController.restoreCompletedTransactionsFailed(withError: error)
 
         XCTAssertTrue(callbackCalled)
     }
 
     func testRestoreCompletedTransactionsFinished_callsCallbackWithNoTransactions() {
-        
+
         var callbackCalled = false
         let restorePurchases = RestorePurchases(atomically: true) { results in
             callbackCalled = true
@@ -151,18 +147,18 @@ class RestorePurchasesControllerTests: XCTestCase {
             XCTAssertEqual(results.count, 0)
         }
         let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)
-        
+
         restorePurchasesController.restoreCompletedTransactionsFinished()
-        
+
         XCTAssertTrue(callbackCalled)
     }
-    
+
     func makeRestorePurchasesController(restorePurchases: RestorePurchases?) -> RestorePurchasesController {
-        
+
         let restorePurchasesController = RestorePurchasesController()
-        
+
         restorePurchasesController.restorePurchases = restorePurchases
-        
+
         return restorePurchasesController
     }
 }

+ 4 - 2
SwiftyStoreKitTests/TestPaymentTransaction.swift

@@ -24,11 +24,13 @@
 
 import StoreKit
 
+// swiftlint:disable variable_name
+
 class TestPaymentTransaction: SKPaymentTransaction {
 
     let _transactionState: SKPaymentTransactionState
     let _payment: SKPayment
-    
+
     init(payment: SKPayment, transactionState: SKPaymentTransactionState) {
         _transactionState = transactionState
         _payment = payment
@@ -37,7 +39,7 @@ class TestPaymentTransaction: SKPaymentTransaction {
     override var payment: SKPayment {
         return _payment
     }
-    
+
     override var transactionState: SKPaymentTransactionState {
         return _transactionState
     }

+ 5 - 3
SwiftyStoreKitTests/TestProduct.swift

@@ -24,14 +24,16 @@
 
 import StoreKit
 
+// swiftlint:disable variable_name
+
 class TestProduct: SKProduct {
-    
+
     var _productIdentifier: String = ""
-    
+
     override var productIdentifier: String {
         return _productIdentifier
     }
-    
+
     init(productIdentifier: String) {
         _productIdentifier = productIdentifier
         super.init()