diff --git a/CHANGELOG.md b/CHANGELOG.md index f095679d3..5e4001328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,15 @@ # Parse-Swift Changelog ### main -[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.6...main) +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.3.0...main) * _Contributing to this repo? Add info about your change here to be included in the next release_ +### 1.3.0 +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.6...1.3.0) + +__Improvements__ +- (Breaking Change) No longer require dispatch to main queue when using ParseInstallation. The side effect of this is bade is no longer retrieved by the SDK. The developer should retrieve the badge count on their own and save it to `ParseInstallation` if they require badge ([#114](https://github.com/parse-community/Parse-Swift/pull/114)), thanks to [Corey Baker](https://github.com/cbaker6). + ### 1.2.6 [Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.5...1.2.6) diff --git a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift index 627dd8b44..7faa68cc7 100644 --- a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift @@ -37,23 +37,19 @@ struct Installation: ParseInstallation { var customKey: String? } -//: WARNING: All calls on Installation need to be done on the main queue -DispatchQueue.main.async { - - /*: Save your first `customKey` value to your `ParseInstallation`. - Performs work on background queue and returns to designated on - designated callbackQueue. If no callbackQueue is specified it - returns to main queue. - */ - Installation.current?.customKey = "myCustomInstallationKey2" - Installation.current?.save { results in - - switch results { - case .success(let updatedInstallation): - print("Successfully save myCustomInstallationKey to ParseServer: \(updatedInstallation)") - case .failure(let error): - print("Failed to update installation: \(error)") - } +/*: Save your first `customKey` value to your `ParseInstallation`. + Performs work on background queue and returns to designated on + designated callbackQueue. If no callbackQueue is specified it + returns to main queue. + */ +Installation.current?.customKey = "myCustomInstallationKey2" +Installation.current?.save { results in + + switch results { + case .success(let updatedInstallation): + print("Successfully save myCustomInstallationKey to ParseServer: \(updatedInstallation)") + case .failure(let error): + print("Failed to update installation: \(error)") } } diff --git a/ParseSwift.podspec b/ParseSwift.podspec index 739fe2dd2..3a7a453b3 100644 --- a/ParseSwift.podspec +++ b/ParseSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "ParseSwift" - s.version = "1.2.6" + s.version = "1.3.0" s.summary = "Parse Pure Swift SDK" s.homepage = "https://github.com/parse-community/Parse-Swift" s.authors = { diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index dd6c07edd..19fd7324a 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -2321,7 +2321,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift; PRODUCT_NAME = ParseSwift; SKIP_INSTALL = YES; @@ -2345,7 +2345,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift; PRODUCT_NAME = ParseSwift; SKIP_INSTALL = YES; @@ -2411,7 +2411,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift; PRODUCT_NAME = ParseSwift; SDKROOT = macosx; @@ -2437,7 +2437,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift; PRODUCT_NAME = ParseSwift; SDKROOT = macosx; @@ -2584,7 +2584,7 @@ INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS"; @@ -2613,7 +2613,7 @@ INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS"; PRODUCT_NAME = ParseSwift; @@ -2640,7 +2640,7 @@ INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS"; @@ -2668,7 +2668,7 @@ INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.2.6; + MARKETING_VERSION = 1.3.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS"; PRODUCT_NAME = ParseSwift; diff --git a/Scripts/jazzy.sh b/Scripts/jazzy.sh index e636dece2..030a5ddbe 100755 --- a/Scripts/jazzy.sh +++ b/Scripts/jazzy.sh @@ -5,7 +5,7 @@ bundle exec jazzy \ --author_url http://parseplatform.org \ --github_url https://github.com/parse-community/Parse-Swift \ --root-url http://parseplatform.org/Parse-Swift/api/ \ - --module-version 1.2.6 \ + --module-version 1.3.0 \ --theme fullwidth \ --skip-undocumented \ --output ./docs/api \ diff --git a/Sources/ParseSwift/Objects/ParseInstallation.swift b/Sources/ParseSwift/Objects/ParseInstallation.swift index 9c03b422f..8532e7409 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation.swift @@ -8,12 +8,6 @@ import Foundation -#if canImport(UIKit) -import UIKit -#elseif canImport(AppKit) -import AppKit -#endif - /** Objects that conform to the `ParseInstallation` protocol have a local representation of an installation persisted to the Parse cloud. This protocol inherits from the @@ -23,8 +17,8 @@ import AppKit A valid `ParseInstallation` can only be instantiated via *current* because the required identifier fields - are readonly. The `timeZone` and `badge` fields are also readonly properties which - are automatically updated to match the device's time zone and application badge + are readonly. The `timeZone` is also a readonly property which + is automatically updated to match the device's time zone when the `ParseInstallation` is saved, thus these fields might not reflect the latest device state if the installation has not recently been saved. @@ -32,8 +26,9 @@ import AppKit the Parse Server can be used to target push notifications. Use `setDeviceToken` to set the `deviceToken` properly. - - warning: Only use `ParseInstallation.current` installations on the main thread as they - require UIApplication for `badge` + - warning: If the use of badge is desired, it should be retrieved by using UIKit, AppKit, etc. and + stored in `ParseInstallation.badge` before saving/updating the installation. + - warning: Linux developers should set `appName`, `appIdentifier`, and `appVersion` manually as `ParseSwift` doesn't have access to Bundle.main. */ @@ -188,9 +183,7 @@ extension ParseInstallation { try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation) #endif //Prepare new installation - DispatchQueue.main.async { - _ = BaseParseInstallation() - } + _ = BaseParseInstallation() } /** @@ -200,7 +193,6 @@ extension ParseInstallation { */ public static var current: Self? { get { - Self.currentInstallationContainer.currentInstallation?.updateBadgeFromDevice() return Self.currentInstallationContainer.currentInstallation } set { @@ -215,7 +207,6 @@ extension ParseInstallation { mutating func updateAutomaticInfo() { updateDeviceTypeFromDevice() updateTimeZoneFromDevice() - updateBadgeFromDevice() updateVersionInfoFromDevice() updateLocaleIdentifierFromDevice() } @@ -239,29 +230,6 @@ extension ParseInstallation { } } - mutating func updateBadgeFromDevice() { - let applicationBadge: Int! - - #if canImport(UIKit) && !os(watchOS) - applicationBadge = UIApplication.shared.applicationIconBadgeNumber - #elseif canImport(AppKit) - guard let currentApplicationBadge = NSApplication.shared.dockTile.badgeLabel else { - //If badgeLabel not set, assume it's 0 - applicationBadge = 0 - return - } - applicationBadge = Int(currentApplicationBadge) - #else - applicationBadge = 0 - #endif - - if badge != applicationBadge { - badge = applicationBadge - //Since this changes, update the Keychain whenever it changes - Self.saveCurrentContainerToKeychain() - } - } - mutating func updateVersionInfoFromDevice() { guard let appInfo = Bundle.main.infoDictionary else { return diff --git a/Sources/ParseSwift/Parse.swift b/Sources/ParseSwift/Parse.swift index 09c65e064..d7755b3a1 100644 --- a/Sources/ParseSwift/Parse.swift +++ b/Sources/ParseSwift/Parse.swift @@ -66,9 +66,7 @@ public struct ParseSwift { ParseStorage.shared.use(keyValueStore ?? InMemoryKeyValueStore()) ParseConfiguration.sessionDelegate = ParseURLSessionDelegate(callbackQueue: .main, authentication: authentication) //Prepare installation - DispatchQueue.main.async { - _ = BaseParseInstallation() - } + _ = BaseParseInstallation() } internal static func initialize(applicationId: String, diff --git a/Sources/ParseSwift/ParseConstants.swift b/Sources/ParseSwift/ParseConstants.swift index 27ccec2e1..c4e3e35fa 100644 --- a/Sources/ParseSwift/ParseConstants.swift +++ b/Sources/ParseSwift/ParseConstants.swift @@ -9,7 +9,7 @@ import Foundation enum ParseConstants { - static let parseVersion = "1.2.6" + static let parseVersion = "1.3.0" static let hashingKey = "parseSwift" static let fileManagementDirectory = "parse/" static let fileManagementPrivateDocumentsDirectory = "Private Documents/" diff --git a/Sources/ParseSwift/Storage/KeychainStore.swift b/Sources/ParseSwift/Storage/KeychainStore.swift index 14d9715e3..9798fc7be 100644 --- a/Sources/ParseSwift/Storage/KeychainStore.swift +++ b/Sources/ParseSwift/Storage/KeychainStore.swift @@ -29,7 +29,7 @@ func getKeychainQueryTemplate(forService service: String) -> [String: String] { first device unlock and are not backed up. */ struct KeychainStore: SecureStorage { - private let synchronizationQueue: DispatchQueue + let synchronizationQueue: DispatchQueue private let keychainQueryTemplate: [String: String] public static var shared = KeychainStore(service: "shared") diff --git a/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift b/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift index 872cd676f..f56b49a86 100644 --- a/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift @@ -152,28 +152,21 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type MockURLProtocol.mockRequests { _ in return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - do { - let saved = try installation.save() - guard let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt) - XCTAssertNil(saved.ACL) - } catch { - XCTFail(error.localizedDescription) + do { + let saved = try installation.save() + guard let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return } - expectation1.fulfill() + guard let originalUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt) + XCTAssertNil(saved.ACL) + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1], timeout: 20.0) } func testFetch() { @@ -182,43 +175,42 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let installation = Installation.current, - let savedObjectId = installation.objectId else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - XCTAssertEqual(savedObjectId, self.testInstallationObjectId) - - var serverResponse = installation - serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - serverResponse.customKey = "newValue" - - MockURLProtocol.mockRequests { _ in - do { - let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } catch { - return nil - } + + guard let installation = Installation.current, + let savedObjectId = installation.objectId else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } + XCTAssertEqual(savedObjectId, self.testInstallationObjectId) + + var serverResponse = installation + serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + serverResponse.customKey = "newValue" + + MockURLProtocol.mockRequests { _ in + do { + let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } catch { + return nil } + } - let publisher = installation.fetchPublisher() - .sink(receiveCompletion: { result in + let publisher = installation.fetchPublisher() + .sink(receiveCompletion: { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } + expectation1.fulfill() - }, receiveValue: { fetched in + }, receiveValue: { fetched in - XCTAssert(fetched.hasSameObjectId(as: serverResponse)) - XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey) - }) - publisher.store(in: &subscriptions) - } + XCTAssert(fetched.hasSameObjectId(as: serverResponse)) + XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey) + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -228,43 +220,41 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard var installation = Installation.current, - let savedObjectId = installation.objectId else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - installation.customKey = "newValue" - XCTAssertEqual(savedObjectId, self.testInstallationObjectId) - - var serverResponse = installation - serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - - MockURLProtocol.mockRequests { _ in - do { - let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } catch { - return nil - } + guard var installation = Installation.current, + let savedObjectId = installation.objectId else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } + installation.customKey = "newValue" + XCTAssertEqual(savedObjectId, self.testInstallationObjectId) + + var serverResponse = installation + serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + + MockURLProtocol.mockRequests { _ in + do { + let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } catch { + return nil } + } - let publisher = installation.savePublisher() - .sink(receiveCompletion: { result in + let publisher = installation.savePublisher() + .sink(receiveCompletion: { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } + expectation1.fulfill() - }, receiveValue: { fetched in + }, receiveValue: { fetched in - XCTAssert(fetched.hasSameObjectId(as: serverResponse)) - XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey) - }) - publisher.store(in: &subscriptions) - } + XCTAssert(fetched.hasSameObjectId(as: serverResponse)) + XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey) + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -274,41 +264,39 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let installation = Installation.current, - let savedObjectId = installation.objectId else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - XCTAssertEqual(savedObjectId, self.testInstallationObjectId) - - var serverResponse = installation - serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - serverResponse.customKey = "newValue" - - MockURLProtocol.mockRequests { _ in - do { - let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } catch { - return nil - } + guard let installation = Installation.current, + let savedObjectId = installation.objectId else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } + XCTAssertEqual(savedObjectId, self.testInstallationObjectId) + + var serverResponse = installation + serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + serverResponse.customKey = "newValue" + + MockURLProtocol.mockRequests { _ in + do { + let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none) + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } catch { + return nil } + } - let publisher = installation.deletePublisher() - .sink(receiveCompletion: { result in + let publisher = installation.deletePublisher() + .sink(receiveCompletion: { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } + expectation1.fulfill() - }, receiveValue: { _ in + }, receiveValue: { _ in - }) - publisher.store(in: &subscriptions) - } + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -318,90 +306,88 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Fetch") - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + guard var installation = Installation.current else { + XCTFail("Should unwrap dates") + expectation1.fulfill() + return + } - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = QueryResponse(results: [installation], count: 1) + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = QueryResponse(results: [installation], count: 1) - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + let publisher = [installation].fetchAllPublisher() + .sink(receiveCompletion: { result in + + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - let publisher = [installation].fetchAllPublisher() - .sink(receiveCompletion: { result in + }, receiveValue: { fetched in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() - - }, receiveValue: { fetched in - - fetched.forEach { - switch $0 { - case .success(let fetched): - XCTAssert(fetched.hasSameObjectId(as: installation)) - guard let fetchedCreatedAt = fetched.createdAt, - let fetchedUpdatedAt = fetched.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = installation.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) - XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installation.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") + fetched.forEach { + switch $0 { + case .success(let fetched): + XCTAssert(fetched.hasSameObjectId(as: installation)) + guard let fetchedCreatedAt = fetched.createdAt, + let fetchedUpdatedAt = fetched.updatedAt else { + XCTFail("Should unwrap dates") expectation1.fulfill() return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() + } + guard let originalCreatedAt = installation.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + expectation1.fulfill() return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") } + XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) + XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installation.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") + expectation1.fulfill() + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + expectation1.fulfill() + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - }) - publisher.store(in: &subscriptions) - } + } + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -411,90 +397,88 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + guard var installation = Installation.current else { + XCTFail("Should unwrap dates") + expectation1.fulfill() + return + } - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = [BatchResponseItem(success: installation, error: nil)] + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = [BatchResponseItem(success: installation, error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + let publisher = [installation].saveAllPublisher() + .sink(receiveCompletion: { result in + + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - let publisher = [installation].saveAllPublisher() - .sink(receiveCompletion: { result in + }, receiveValue: { saved in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() - - }, receiveValue: { saved in - - saved.forEach { - switch $0 { - case .success(let saved): - XCTAssert(saved.hasSameObjectId(as: installation)) - guard let savedCreatedAt = saved.createdAt, - let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = installation.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(savedCreatedAt, originalCreatedAt) - XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installation.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") + saved.forEach { + switch $0 { + case .success(let saved): + XCTAssert(saved.hasSameObjectId(as: installation)) + guard let savedCreatedAt = saved.createdAt, + let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") expectation1.fulfill() return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() + } + guard let originalCreatedAt = installation.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + expectation1.fulfill() return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") } + XCTAssertEqual(savedCreatedAt, originalCreatedAt) + XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installation.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") + expectation1.fulfill() + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + expectation1.fulfill() + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - }) - publisher.store(in: &subscriptions) - } + } + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -504,44 +488,42 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + guard let installation = Installation.current else { + XCTFail("Should unwrap dates") + expectation1.fulfill() + return + } - let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] + let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - let publisher = [installation].deleteAllPublisher() - .sink(receiveCompletion: { result in + let publisher = [installation].deleteAllPublisher() + .sink(receiveCompletion: { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } + expectation1.fulfill() - }, receiveValue: { deleted in - deleted.forEach { - if case let .failure(error) = $0 { - XCTFail("Should have deleted: \(error.localizedDescription)") - } + }, receiveValue: { deleted in + deleted.forEach { + if case let .failure(error) = $0 { + XCTFail("Should have deleted: \(error.localizedDescription)") } - }) - publisher.store(in: &subscriptions) - } + } + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } } diff --git a/Tests/ParseSwiftTests/ParseInstallationTests.swift b/Tests/ParseSwiftTests/ParseInstallationTests.swift index 37c2c01c1..ecedd3a43 100644 --- a/Tests/ParseSwiftTests/ParseInstallationTests.swift +++ b/Tests/ParseSwiftTests/ParseInstallationTests.swift @@ -7,11 +7,6 @@ // import Foundation -#if canImport(UIKit) -import UIKit -#elseif canImport(AppKit) -import AppKit -#endif import XCTest @testable import ParseSwift @@ -131,28 +126,21 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l } func testNewInstallationIdentifierIsLowercase() { - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let installationIdFromContainer - = Installation.currentInstallationContainer.installationId else { - XCTFail("Should have retreived installationId from container") - expectation1.fulfill() - return - } - - XCTAssertEqual(installationIdFromContainer, installationIdFromContainer.lowercased()) + guard let installationIdFromContainer + = Installation.currentInstallationContainer.installationId else { + XCTFail("Should have retreived installationId from container") + return + } - guard let installationIdFromCurrent = Installation.current?.installationId else { - XCTFail("Should have retreived installationId from container") - expectation1.fulfill() - return - } + XCTAssertEqual(installationIdFromContainer, installationIdFromContainer.lowercased()) - XCTAssertEqual(installationIdFromCurrent, installationIdFromCurrent.lowercased()) - XCTAssertEqual(installationIdFromContainer, installationIdFromCurrent) - expectation1.fulfill() + guard let installationIdFromCurrent = Installation.current?.installationId else { + XCTFail("Should have retreived installationId from container") + return } - wait(for: [expectation1], timeout: 20.0) + + XCTAssertEqual(installationIdFromCurrent, installationIdFromCurrent.lowercased()) + XCTAssertEqual(installationIdFromContainer, installationIdFromCurrent) } func testDeviceTokenAsString() throws { @@ -162,21 +150,15 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l } func testInstallationMutableValuesCanBeChangedInMemory() { - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let originalInstallation = Installation.current else { - XCTFail("All of these Installation values should have unwraped") - expectation1.fulfill() - return - } - - Installation.current?.customKey = "Changed" - Installation.current?.setDeviceToken(Data([0, 1, 127, 128, 255])) - XCTAssertNotEqual(originalInstallation.customKey, Installation.current?.customKey) - XCTAssertNotEqual(originalInstallation.deviceToken, Installation.current?.customKey) - expectation1.fulfill() + guard let originalInstallation = Installation.current else { + XCTFail("All of these Installation values should have unwraped") + return } - wait(for: [expectation1], timeout: 20.0) + + Installation.current?.customKey = "Changed" + Installation.current?.setDeviceToken(Data([0, 1, 127, 128, 255])) + XCTAssertNotEqual(originalInstallation.customKey, Installation.current?.customKey) + XCTAssertNotEqual(originalInstallation.deviceToken, Installation.current?.customKey) } func testInstallationCustomValuesNotSavedToKeychain() { @@ -193,126 +175,87 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l #if !os(Linux) && !os(Android) func testInstallationImmutableFieldsCannotBeChangedInMemory() { - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let originalInstallation = Installation.current, - let originalInstallationId = originalInstallation.installationId, - let originalDeviceType = originalInstallation.deviceType, - let originalBadge = originalInstallation.badge, - let originalTimeZone = originalInstallation.timeZone, - let originalAppName = originalInstallation.appName, - let originalAppIdentifier = originalInstallation.appIdentifier, - let originalAppVersion = originalInstallation.appVersion, - let originalParseVersion = originalInstallation.parseVersion, - let originalLocaleIdentifier = originalInstallation.localeIdentifier - else { - XCTFail("All of these Installation values should have unwraped") - expectation1.fulfill() - return - } - - Installation.current?.installationId = "changed" - Installation.current?.deviceType = "changed" - Installation.current?.badge = 500 - Installation.current?.timeZone = "changed" - Installation.current?.appName = "changed" - Installation.current?.appIdentifier = "changed" - Installation.current?.appVersion = "changed" - Installation.current?.parseVersion = "changed" - Installation.current?.localeIdentifier = "changed" - - XCTAssertEqual(originalInstallationId, Installation.current?.installationId) - XCTAssertEqual(originalDeviceType, Installation.current?.deviceType) - XCTAssertEqual(originalBadge, Installation.current?.badge) - XCTAssertEqual(originalTimeZone, Installation.current?.timeZone) - XCTAssertEqual(originalAppName, Installation.current?.appName) - XCTAssertEqual(originalAppIdentifier, Installation.current?.appIdentifier) - XCTAssertEqual(originalAppVersion, Installation.current?.appVersion) - XCTAssertEqual(originalParseVersion, Installation.current?.parseVersion) - XCTAssertEqual(originalLocaleIdentifier, Installation.current?.localeIdentifier) - expectation1.fulfill() + guard let originalInstallation = Installation.current, + let originalInstallationId = originalInstallation.installationId, + let originalDeviceType = originalInstallation.deviceType, + let originalTimeZone = originalInstallation.timeZone, + let originalAppName = originalInstallation.appName, + let originalAppIdentifier = originalInstallation.appIdentifier, + let originalAppVersion = originalInstallation.appVersion, + let originalParseVersion = originalInstallation.parseVersion, + let originalLocaleIdentifier = originalInstallation.localeIdentifier + else { + XCTFail("All of these Installation values should have unwraped") + return } - wait(for: [expectation1], timeout: 20.0) + + Installation.current?.installationId = "changed" + Installation.current?.deviceType = "changed" + Installation.current?.badge = 500 + Installation.current?.timeZone = "changed" + Installation.current?.appName = "changed" + Installation.current?.appIdentifier = "changed" + Installation.current?.appVersion = "changed" + Installation.current?.parseVersion = "changed" + Installation.current?.localeIdentifier = "changed" + + XCTAssertEqual(originalInstallationId, Installation.current?.installationId) + XCTAssertEqual(originalDeviceType, Installation.current?.deviceType) + XCTAssertEqual(500, Installation.current?.badge) + XCTAssertEqual(originalTimeZone, Installation.current?.timeZone) + XCTAssertEqual(originalAppName, Installation.current?.appName) + XCTAssertEqual(originalAppIdentifier, Installation.current?.appIdentifier) + XCTAssertEqual(originalAppVersion, Installation.current?.appVersion) + XCTAssertEqual(originalParseVersion, Installation.current?.parseVersion) + XCTAssertEqual(originalLocaleIdentifier, Installation.current?.localeIdentifier) } // swiftlint:disable:next function_body_length func testInstallationImmutableFieldsCannotBeChangedInKeychain() { - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let originalInstallation = Installation.current, - let originalInstallationId = originalInstallation.installationId, - let originalDeviceType = originalInstallation.deviceType, - let originalBadge = originalInstallation.badge, - let originalTimeZone = originalInstallation.timeZone, - let originalAppName = originalInstallation.appName, - let originalAppIdentifier = originalInstallation.appIdentifier, - let originalAppVersion = originalInstallation.appVersion, - let originalParseVersion = originalInstallation.parseVersion, - let originalLocaleIdentifier = originalInstallation.localeIdentifier - else { - XCTFail("All of these Installation values should have unwraped") - expectation1.fulfill() - return - } + guard let originalInstallation = Installation.current, + let originalInstallationId = originalInstallation.installationId, + let originalDeviceType = originalInstallation.deviceType, + let originalTimeZone = originalInstallation.timeZone, + let originalAppName = originalInstallation.appName, + let originalAppIdentifier = originalInstallation.appIdentifier, + let originalAppVersion = originalInstallation.appVersion, + let originalParseVersion = originalInstallation.parseVersion, + let originalLocaleIdentifier = originalInstallation.localeIdentifier + else { + XCTFail("All of these Installation values should have unwraped") + return + } - Installation.current?.installationId = "changed" - Installation.current?.deviceType = "changed" - Installation.current?.badge = 500 - Installation.current?.timeZone = "changed" - Installation.current?.appName = "changed" - Installation.current?.appIdentifier = "changed" - Installation.current?.appVersion = "changed" - Installation.current?.parseVersion = "changed" - Installation.current?.localeIdentifier = "changed" + Installation.current?.installationId = "changed" + Installation.current?.deviceType = "changed" + Installation.current?.badge = 500 + Installation.current?.timeZone = "changed" + Installation.current?.appName = "changed" + Installation.current?.appIdentifier = "changed" + Installation.current?.appVersion = "changed" + Installation.current?.parseVersion = "changed" + Installation.current?.localeIdentifier = "changed" - Installation.saveCurrentContainerToKeychain() + Installation.saveCurrentContainerToKeychain() - #if !os(Linux) && !os(Android) - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else { - expectation1.fulfill() - return - } - XCTAssertEqual(originalInstallationId, keychainInstallation.currentInstallation?.installationId) - XCTAssertEqual(originalDeviceType, keychainInstallation.currentInstallation?.deviceType) - XCTAssertEqual(originalBadge, keychainInstallation.currentInstallation?.badge) - XCTAssertEqual(originalTimeZone, keychainInstallation.currentInstallation?.timeZone) - XCTAssertEqual(originalAppName, keychainInstallation.currentInstallation?.appName) - XCTAssertEqual(originalAppIdentifier, keychainInstallation.currentInstallation?.appIdentifier) - XCTAssertEqual(originalAppVersion, keychainInstallation.currentInstallation?.appVersion) - XCTAssertEqual(originalParseVersion, keychainInstallation.currentInstallation?.parseVersion) - XCTAssertEqual(originalLocaleIdentifier, keychainInstallation.currentInstallation?.localeIdentifier) - #endif - expectation1.fulfill() + #if !os(Linux) && !os(Android) + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else { + XCTFail("Should have unwrapped") + return } - wait(for: [expectation1], timeout: 20.0) - } - #endif - - func testInstallationHasApplicationBadge() { - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - #if canImport(UIKit) && !os(watchOS) - UIApplication.shared.applicationIconBadgeNumber = 10 - guard let installationBadge = Installation.current?.badge else { - XCTFail("Should have retreived badge") - expectation1.fulfill() - return - } - XCTAssertEqual(installationBadge, 10) - #elseif canImport(AppKit) - NSApplication.shared.dockTile.badgeLabel = "10" - guard let installationBadge = Installation.current?.badge else { - XCTFail("Should have retreived badge") - expectation1.fulfill() - return - } - XCTAssertEqual(installationBadge, 10) + XCTAssertEqual(originalInstallationId, keychainInstallation.currentInstallation?.installationId) + XCTAssertEqual(originalDeviceType, keychainInstallation.currentInstallation?.deviceType) + XCTAssertEqual(500, keychainInstallation.currentInstallation?.badge) + XCTAssertEqual(originalTimeZone, keychainInstallation.currentInstallation?.timeZone) + XCTAssertEqual(originalAppName, keychainInstallation.currentInstallation?.appName) + XCTAssertEqual(originalAppIdentifier, keychainInstallation.currentInstallation?.appIdentifier) + XCTAssertEqual(originalAppVersion, keychainInstallation.currentInstallation?.appVersion) + XCTAssertEqual(originalParseVersion, keychainInstallation.currentInstallation?.parseVersion) + XCTAssertEqual(originalLocaleIdentifier, keychainInstallation.currentInstallation?.localeIdentifier) #endif - expectation1.fulfill() - } - wait(for: [expectation1], timeout: 20.0) } + #endif func testUpdate() { var installation = Installation() @@ -336,43 +279,31 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l MockURLProtocol.mockRequests { _ in return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - do { - let saved = try installation.save() - guard let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt) - XCTAssertNil(saved.ACL) - } catch { - XCTFail(error.localizedDescription) + + do { + let saved = try installation.save() + guard let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return } - expectation1.fulfill() + guard let originalUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt) + XCTAssertNil(saved.ACL) + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1], timeout: 20.0) } func testUpdateToCurrentInstallation() { testUpdate() - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let savedObjectId = Installation.current?.objectId else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(savedObjectId, self.testInstallationObjectId) - expectation1.fulfill() + guard let savedObjectId = Installation.current?.objectId else { + XCTFail("Should unwrap dates") + return } - wait(for: [expectation1], timeout: 20.0) + XCTAssertEqual(savedObjectId, self.testInstallationObjectId) } // swiftlint:disable:next function_body_length @@ -501,36 +432,105 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l testUpdate() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let installation = Installation.current, - let savedObjectId = installation.objectId else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - XCTAssertEqual(savedObjectId, self.testInstallationObjectId) + guard let installation = Installation.current, + let savedObjectId = installation.objectId else { + XCTFail("Should unwrap") + return + } + XCTAssertEqual(savedObjectId, self.testInstallationObjectId) - var installationOnServer = installation - installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installationOnServer.customKey = "newValue" + var installationOnServer = installation + installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installationOnServer.customKey = "newValue" - let encoded: Data! - do { - encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) - //Get dates in correct format from ParseDecoding strategy - installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() + let encoded: Data! + do { + encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) + //Get dates in correct format from ParseDecoding strategy + installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + do { + let fetched = try installation.fetch(options: [.useMasterKey]) + XCTAssert(fetched.hasSameObjectId(as: installationOnServer)) + guard let fetchedCreatedAt = fetched.createdAt, + let fetchedUpdatedAt = fetched.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = installationOnServer.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installationOnServer.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) + XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") return } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + //Should be updated in Keychain + #if !os(Linux) && !os(Android) + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + return } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + } catch { + XCTFail(error.localizedDescription) + } + } - do { - let fetched = try installation.fetch(options: [.useMasterKey]) + func testFetchUpdatedCurrentInstallationAsync() { // swiftlint:disable:this function_body_length + testUpdate() + MockURLProtocol.removeAll() + + let expectation1 = XCTestExpectation(description: "Update installation1") + + guard let installation = Installation.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } + + var installationOnServer = installation + installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installationOnServer.customKey = "newValue" + + let encoded: Data! + do { + encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) + //Get dates in correct format from ParseDecoding strategy + installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + installation.fetch(options: [], callbackQueue: .main) { result in + + switch result { + case .success(let fetched): XCTAssert(fetched.hasSameObjectId(as: installationOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { @@ -558,8 +558,8 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l } XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - //Should be updated in Keychain #if !os(Linux) && !os(Android) + //Should be updated in Keychain guard let keychainInstallation: CurrentInstallationContainer = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { @@ -569,96 +569,14 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l } XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) #endif - } catch { + case .failure(let error): XCTFail(error.localizedDescription) } - expectation1.fulfill() } wait(for: [expectation1], timeout: 20.0) } - func testFetchUpdatedCurrentInstallationAsync() { // swiftlint:disable:this function_body_length - testUpdate() - MockURLProtocol.removeAll() - - let expectation1 = XCTestExpectation(description: "Update installation1") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - - var installationOnServer = installation - installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installationOnServer.customKey = "newValue" - - let encoded: Data! - do { - encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) - //Get dates in correct format from ParseDecoding strategy - installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - - installation.fetch(options: [], callbackQueue: .main) { result in - - switch result { - case .success(let fetched): - XCTAssert(fetched.hasSameObjectId(as: installationOnServer)) - guard let fetchedCreatedAt = fetched.createdAt, - let fetchedUpdatedAt = fetched.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = installationOnServer.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installationOnServer.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) - XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation1.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail(error.localizedDescription) - } - expectation1.fulfill() - } - } - wait(for: [expectation1], timeout: 20.0) - } - func testDeleteCommand() { var installation = Installation() let objectId = "yarr" @@ -679,29 +597,23 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l func testDelete() { testUpdate() - let expectation1 = XCTestExpectation(description: "Delete installation1") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - - do { - try installation.delete(options: []) - } catch { - XCTFail(error.localizedDescription) - } - - do { - try installation.delete(options: [.useMasterKey]) - } catch { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + guard let installation = Installation.current else { + XCTFail("Should unwrap dates") + return + } + + do { + try installation.delete(options: []) + } catch { + XCTFail(error.localizedDescription) + } + + do { + try installation.delete(options: [.useMasterKey]) + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1], timeout: 20.0) } func testDeleteAsyncMainQueue() { @@ -709,36 +621,34 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l MockURLProtocol.removeAll() let expectation1 = XCTestExpectation(description: "Delete installation1") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } + guard let installation = Installation.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } - var installationOnServer = installation - installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + var installationOnServer = installation + installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - let encoded: Data! - do { - encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) - //Get dates in correct format from ParseDecoding strategy - installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none) + //Get dates in correct format from ParseDecoding strategy + installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - installation.delete { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) - } - expectation1.fulfill() + installation.delete { result in + if case let .failure(error) = result { + XCTFail(error.localizedDescription) } + expectation1.fulfill() } wait(for: [expectation1], timeout: 20.0) } @@ -748,36 +658,112 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l testUpdate() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Fetch installation1") + guard var installation = Installation.current else { + XCTFail("Should unwrap dates") + return + } - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = QueryResponse(results: [installation], count: 1) - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = QueryResponse(results: [installation], count: 1) + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + do { + let fetched = try [installation].fetchAll() + fetched.forEach { + switch $0 { + case .success(let fetched): + XCTAssert(fetched.hasSameObjectId(as: installation)) + guard let fetchedCreatedAt = fetched.createdAt, + let fetchedUpdatedAt = fetched.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = installation.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) + XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installation.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") + } } + } catch { + XCTFail(error.localizedDescription) + } + } - do { - let fetched = try [installation].fetchAll() + // swiftlint:disable:next function_body_length + func testFetchAllAsyncMainQueue() { + testUpdate() + MockURLProtocol.removeAll() + + let expectation1 = XCTestExpectation(description: "Fetch installation1") + guard var installation = Installation.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } + + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = QueryResponse(results: [installation], count: 1) + + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + [installation].fetchAll { results in + switch results { + + case .success(let fetched): fetched.forEach { switch $0 { case .success(let fetched): @@ -812,7 +798,8 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l //Should be updated in Keychain guard let keychainInstallation: CurrentInstallationContainer = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + let keychainUpdatedCurrentDate = keychainInstallation + .currentInstallation?.updatedAt else { XCTFail("Should get object from Keychain") expectation1.fulfill() return @@ -823,106 +810,14 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() } wait(for: [expectation1], timeout: 20.0) } - // swiftlint:disable:next function_body_length - func testFetchAllAsyncMainQueue() { - testUpdate() - MockURLProtocol.removeAll() - - let expectation1 = XCTestExpectation(description: "Fetch installation1") - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } - - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = QueryResponse(results: [installation], count: 1) - - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - - [installation].fetchAll { results in - switch results { - - case .success(let fetched): - fetched.forEach { - switch $0 { - case .success(let fetched): - XCTAssert(fetched.hasSameObjectId(as: installation)) - guard let fetchedCreatedAt = fetched.createdAt, - let fetchedUpdatedAt = fetched.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = installation.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) - XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installation.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation1.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation - .currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - expectation1.fulfill() - } - } - wait(for: [expectation1], timeout: 20.0) - } - func testSaveCommand() throws { let installation = Installation() let command = try installation.saveCommand() @@ -951,39 +846,162 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l testUpdate() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Fetch installation1") - let expectation2 = XCTestExpectation(description: "Fetch installation2") + guard var installation = Installation.current else { + XCTFail("Should unwrap dates") + return + } - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - expectation2.fulfill() - return - } + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = [BatchResponseItem(success: installation, error: nil)] - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = [BatchResponseItem(success: installation, error: nil)] + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return + do { + let saved = try [installation].saveAll() + saved.forEach { + switch $0 { + case .success(let saved): + XCTAssert(saved.hasSameObjectId(as: installation)) + guard let savedCreatedAt = saved.createdAt, + let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = installation.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(savedCreatedAt, originalCreatedAt) + XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installation.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") + } } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } catch { + XCTFail(error.localizedDescription) + } + + do { + let saved2 = try [installation].saveAll(transaction: true) + saved2.forEach { + switch $0 { + case .success(let saved): + XCTAssert(saved.hasSameObjectId(as: installation)) + guard let savedCreatedAt = saved.createdAt, + let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = installation.createdAt, + let originalUpdatedAt = installation.updatedAt, + let serverUpdatedAt = installation.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(savedCreatedAt, originalCreatedAt) + XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(Installation.current?.customKey, installation.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = Installation.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainInstallation: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), + let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") + } } + } catch { + XCTFail(error.localizedDescription) + } + } - do { - let saved = try [installation].saveAll() + // swiftlint:disable:next function_body_length + func testSaveAllAsyncMainQueue() { + testUpdate() + MockURLProtocol.removeAll() + + let expectation1 = XCTestExpectation(description: "Fetch installation1") + let expectation2 = XCTestExpectation(description: "Fetch installation2") + guard var installation = Installation.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + expectation2.fulfill() + return + } + + installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) + installation.customKey = "newValue" + let installationOnServer = [BatchResponseItem(success: installation, error: nil)] + + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(installation) + installation = try installation.getDecoder().decode(Installation.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + expectation2.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + [installation].saveAll { results in + switch results { + + case .success(let saved): saved.forEach { switch $0 { case .success(let saved): @@ -1013,12 +1031,12 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l return } XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - #if !os(Linux) && !os(Android) //Should be updated in Keychain guard let keychainInstallation: CurrentInstallationContainer = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + let keychainUpdatedCurrentDate = keychainInstallation + .currentInstallation?.updatedAt else { XCTFail("Should get object from Keychain") expectation1.fulfill() return @@ -1029,15 +1047,17 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() + } - do { - let saved2 = try [installation].saveAll(transaction: true) - saved2.forEach { + [installation].saveAll(transaction: true) { results in + switch results { + + case .success(let saved): + saved.forEach { switch $0 { case .success(let saved): XCTAssert(saved.hasSameObjectId(as: installation)) @@ -1051,7 +1071,7 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l let originalUpdatedAt = installation.updatedAt, let serverUpdatedAt = installation.updatedAt else { XCTFail("Should unwrap dates") - expectation2.fulfill() + expectation2.fulfill() return } XCTAssertEqual(savedCreatedAt, originalCreatedAt) @@ -1066,14 +1086,14 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l return } XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - #if !os(Linux) && !os(Android) //Should be updated in Keychain guard let keychainInstallation: CurrentInstallationContainer = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else { + let keychainUpdatedCurrentDate = keychainInstallation + .currentInstallation?.updatedAt else { XCTFail("Should get object from Keychain") - expectation2.fulfill() + expectation2.fulfill() return } XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) @@ -1082,281 +1102,118 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } expectation2.fulfill() } wait(for: [expectation1, expectation2], timeout: 20.0) } - // swiftlint:disable:next function_body_length - func testSaveAllAsyncMainQueue() { + func testDeleteAll() { testUpdate() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Fetch installation1") - let expectation2 = XCTestExpectation(description: "Fetch installation2") - DispatchQueue.main.async { - guard var installation = Installation.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - expectation2.fulfill() - return - } + guard let installation = Installation.current else { + XCTFail("Should unwrap dates") + return + } - installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300) - installation.customKey = "newValue" - let installationOnServer = [BatchResponseItem(success: installation, error: nil)] + let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(installation) - installation = try installation.getDecoder().decode(Installation.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - - [installation].saveAll { results in - switch results { + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - case .success(let saved): - saved.forEach { - switch $0 { - case .success(let saved): - XCTAssert(saved.hasSameObjectId(as: installation)) - guard let savedCreatedAt = saved.createdAt, - let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = installation.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(savedCreatedAt, originalCreatedAt) - XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installation.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation1.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation - .currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") + do { + let deleted = try [installation].deleteAll() + deleted.forEach { + if case let .failure(error) = $0 { + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation1.fulfill() } + } catch { + XCTFail(error.localizedDescription) + } - [installation].saveAll(transaction: true) { results in - switch results { - - case .success(let saved): - saved.forEach { - switch $0 { - case .success(let saved): - XCTAssert(saved.hasSameObjectId(as: installation)) - guard let savedCreatedAt = saved.createdAt, - let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation2.fulfill() - return - } - guard let originalCreatedAt = installation.createdAt, - let originalUpdatedAt = installation.updatedAt, - let serverUpdatedAt = installation.updatedAt else { - XCTFail("Should unwrap dates") - expectation2.fulfill() - return - } - XCTAssertEqual(savedCreatedAt, originalCreatedAt) - XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(Installation.current?.customKey, installation.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = Installation.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation2.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainInstallation: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation), - let keychainUpdatedCurrentDate = keychainInstallation - .currentInstallation?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation2.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") + do { + let deleted = try [installation].deleteAll(transaction: true) + deleted.forEach { + if case let .failure(error) = $0 { + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation2.fulfill() } + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1, expectation2], timeout: 20.0) } - func testDeleteAll() { + func testDeleteAllAsyncMainQueue() { testUpdate() MockURLProtocol.removeAll() let expectation1 = XCTestExpectation(description: "Delete installation1") let expectation2 = XCTestExpectation(description: "Delete installation2") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - expectation2.fulfill() - return - } + guard let installation = Installation.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + expectation2.fulfill() + return + } - let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] + let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + expectation2.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - do { - let deleted = try [installation].deleteAll() + [installation].deleteAll { results in + switch results { + + case .success(let deleted): deleted.forEach { if case let .failure(error) = $0 { XCTFail("Should have deleted: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation1.fulfill() + } - do { - let deleted = try [installation].deleteAll(transaction: true) + [installation].deleteAll(transaction: true) { results in + switch results { + + case .success(let deleted): deleted.forEach { if case let .failure(error) = $0 { XCTFail("Should have deleted: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation2.fulfill() } wait(for: [expectation1, expectation2], timeout: 20.0) } - - func testDeleteAllAsyncMainQueue() { - testUpdate() - MockURLProtocol.removeAll() - - let expectation1 = XCTestExpectation(description: "Delete installation1") - let expectation2 = XCTestExpectation(description: "Delete installation2") - DispatchQueue.main.async { - guard let installation = Installation.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - expectation2.fulfill() - return - } - - let installationOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(installationOnServer) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - - [installation].deleteAll { results in - switch results { - - case .success(let deleted): - deleted.forEach { - if case let .failure(error) = $0 { - XCTFail("Should have deleted: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have deleted: \(error.localizedDescription)") - } - expectation1.fulfill() - } - - [installation].deleteAll(transaction: true) { results in - switch results { - - case .success(let deleted): - deleted.forEach { - if case let .failure(error) = $0 { - XCTFail("Should have deleted: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have deleted: \(error.localizedDescription)") - } - expectation2.fulfill() - } - } - wait(for: [expectation1, expectation2], timeout: 20.0) - } } // swiftlint:disable:this file_length diff --git a/Tests/ParseSwiftTests/ParseUserCombineTests.swift b/Tests/ParseSwiftTests/ParseUserCombineTests.swift index 5a37c000f..add0ac8e0 100644 --- a/Tests/ParseSwiftTests/ParseUserCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCombineTests.swift @@ -293,47 +293,49 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } let expectation1 = XCTestExpectation(description: "Logout user1") - DispatchQueue.main.async { - guard let oldInstallationId = BaseParseInstallation.current?.installationId else { - XCTFail("Should have unwrapped") + guard let oldInstallationId = BaseParseInstallation.current?.installationId else { + XCTFail("Should have unwrapped") + expectation1.fulfill() + return + } + let publisher = User.logoutPublisher() + .sink(receiveCompletion: { result in + + if case let .failure(error) = result { + XCTFail(error.localizedDescription) + } expectation1.fulfill() - return - } - let publisher = User.logoutPublisher() - .sink(receiveCompletion: { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) + }, receiveValue: { _ in + if let userFromKeychain = BaseParseUser.current { + XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") + } + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + if let installationFromMemory: CurrentInstallationContainer + = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { + if installationFromMemory.installationId == oldInstallationId + || installationFromMemory.installationId == nil { + XCTFail("\(installationFromMemory) wasn't deleted and recreated in memory during logout") } - expectation1.fulfill() - - }, receiveValue: { _ in - if let userFromKeychain = BaseParseUser.current { - XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") + } else { + XCTFail("Should have a new installation") } - DispatchQueue.main.async { - if let installationFromMemory: CurrentInstallationContainer - = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromMemory.installationId == oldInstallationId - && installationFromMemory.installationId != nil { - XCTFail("\(installationFromMemory) wasn't deleted and recreated in memory during logout") - } - } - #if !os(Linux) && !os(Android) - if let installationFromKeychain: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromKeychain.installationId == oldInstallationId - && installationFromKeychain.installationId != nil { - // swiftlint:disable:next line_length - XCTFail("\(installationFromKeychain) wasn't deleted and recreated in Keychain during logout") - } + #if !os(Linux) && !os(Android) + if let installationFromKeychain: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { + if installationFromKeychain.installationId == oldInstallationId + || installationFromKeychain.installationId == nil { + XCTFail("\(installationFromKeychain) wasn't deleted & recreated in Keychain during logout") } - #endif + } else { + XCTFail("Should have a new installation") } - }) - publisher.store(in: &subscriptions) - } + #endif + expectation1.fulfill() + } + }) + publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) } @@ -355,6 +357,11 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } let expectation1 = XCTestExpectation(description: "Logout user1") + guard let oldInstallationId = BaseParseInstallation.current?.installationId else { + XCTFail("Should have unwrapped") + expectation1.fulfill() + return + } let publisher = User.logoutPublisher() .sink(receiveCompletion: { result in @@ -365,22 +372,34 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le if let userFromKeychain = BaseParseUser.current { XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") } + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + if let installationFromMemory: CurrentInstallationContainer + = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { + if installationFromMemory.installationId == oldInstallationId + || installationFromMemory.installationId == nil { + XCTFail("\(installationFromMemory) wasn't deleted & recreated in memory during logout") + } + } else { + XCTFail("Should have a new installation") + } - if let installationFromMemory: CurrentInstallationContainer - = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - XCTFail("\(installationFromMemory) wasn't deleted from memory during logout") - } - - #if !os(Linux) && !os(Android) - if let installationFromKeychain: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - XCTFail("\(installationFromKeychain) wasn't deleted from Keychain during logout") + #if !os(Linux) && !os(Android) + if let installationFromKeychain: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { + if installationFromKeychain.installationId == oldInstallationId + || installationFromKeychain.installationId == nil { + // swiftlint:disable:next line_length + XCTFail("\(installationFromKeychain) wasn't deleted & recreated in Keychain during logout") + } + } else { + XCTFail("Should have a new installation") + } + #endif + expectation1.fulfill() } - #endif - expectation1.fulfill() - }, receiveValue: { _ in XCTFail("Should have thrown ParseError") + expectation1.fulfill() }) publisher.store(in: &subscriptions) wait(for: [expectation1], timeout: 20.0) diff --git a/Tests/ParseSwiftTests/ParseUserTests.swift b/Tests/ParseSwiftTests/ParseUserTests.swift index 10a885d74..111fb66e6 100644 --- a/Tests/ParseSwiftTests/ParseUserTests.swift +++ b/Tests/ParseSwiftTests/ParseUserTests.swift @@ -1094,75 +1094,84 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length return nil } } - - DispatchQueue.main.async { - guard let oldInstallationId = BaseParseInstallation.current?.installationId else { - XCTFail("Should have unwrapped") - return + let expectation1 = XCTestExpectation(description: "Logout user1") + guard let oldInstallationId = BaseParseInstallation.current?.installationId else { + XCTFail("Should have unwrapped") + expectation1.fulfill() + return + } + do { + try User.logout() + if let userFromKeychain = BaseParseUser.current { + XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") } - do { - try User.logout() - if let userFromKeychain = BaseParseUser.current { - XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") - } - DispatchQueue.main.async { - if let installationFromKeychain = BaseParseInstallation.current { + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + if let installationFromKeychain = BaseParseInstallation.current { + if installationFromKeychain.installationId == oldInstallationId - && installationFromKeychain.installationId != nil { + || installationFromKeychain.installationId == nil { XCTFail("\(installationFromKeychain) wasn't deleted then created in Keychain during logout") } - } + + } else { + XCTFail("Should have a new installation") } - } catch { - XCTFail(error.localizedDescription) + expectation1.fulfill() } + } catch { + XCTFail(error.localizedDescription) + expectation1.fulfill() } + wait(for: [expectation1], timeout: 20.0) } func logoutAsync(callbackQueue: DispatchQueue) { let expectation1 = XCTestExpectation(description: "Logout user1") - DispatchQueue.main.async { - guard let oldInstallationId = BaseParseInstallation.current?.installationId else { - XCTFail("Should have unwrapped") - expectation1.fulfill() - return - } + guard let oldInstallationId = BaseParseInstallation.current?.installationId else { + XCTFail("Should have unwrapped") + expectation1.fulfill() + return + } - User.logout(callbackQueue: callbackQueue) { result in + User.logout(callbackQueue: callbackQueue) { result in - switch result { + switch result { + + case .success: + if let userFromKeychain = BaseParseUser.current { + XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") + } + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + if let installationFromMemory: CurrentInstallationContainer + = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - case .success: - if let userFromKeychain = BaseParseUser.current { - XCTFail("\(userFromKeychain) wasn't deleted from Keychain during logout") - } - DispatchQueue.main.async { - if let installationFromMemory: CurrentInstallationContainer - = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { if installationFromMemory.installationId == oldInstallationId - && installationFromMemory.installationId != nil { - // swiftlint:disable:next line_length - XCTFail("\(installationFromMemory) wasn't deleted and recreated in memory during logout") + || installationFromMemory.installationId == nil { + XCTFail("\(installationFromMemory) wasn't deleted & recreated in memory during logout") } - } + } else { + XCTFail("Should have a new installation") + } - #if !os(Linux) && !os(Android) - if let installationFromKeychain: CurrentInstallationContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { + #if !os(Linux) && !os(Android) + if let installationFromKeychain: CurrentInstallationContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { if installationFromKeychain.installationId == oldInstallationId - && installationFromKeychain.installationId != nil { + || installationFromKeychain.installationId == nil { // swiftlint:disable:next line_length - XCTFail("\(installationFromKeychain) wasn't deleted and recreated in Keychain during logout") + XCTFail("\(installationFromKeychain) wasn't deleted & recreated in Keychain during logout") } - } - #endif + } else { + XCTFail("Should have a new installation") } - - case .failure(let error): - XCTFail(error.localizedDescription) + #endif + expectation1.fulfill() } + case .failure(let error): + XCTFail(error.localizedDescription) expectation1.fulfill() } } @@ -1445,105 +1454,174 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length func testDelete() { testLogin() + let expectation1 = XCTestExpectation(description: "Delete user") + guard let user = User.current else { + XCTFail("Should unwrap dates") + expectation1.fulfill() + return + } + + do { + try user.delete(options: []) + } catch { + XCTFail(error.localizedDescription) + } + + do { + try user.delete(options: [.useMasterKey]) + } catch { + XCTFail(error.localizedDescription) + } + } + + func testDeleteAsyncMainQueue() { + testLogin() + MockURLProtocol.removeAll() + let expectation1 = XCTestExpectation(description: "Delete installation1") - DispatchQueue.main.async { - guard let user = User.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + guard let user = User.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } - do { - try user.delete(options: []) - } catch { - XCTFail(error.localizedDescription) - } + var userOnServer = user + userOnServer.updatedAt = user.updatedAt?.addingTimeInterval(+300) - do { - try user.delete(options: [.useMasterKey]) - } catch { + let encoded: Data! + do { + encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none) + //Get dates in correct format from ParseDecoding strategy + userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } + + user.delete { result in + if case let .failure(error) = result { XCTFail(error.localizedDescription) } - expectation1.fulfill() } wait(for: [expectation1], timeout: 20.0) } - func testDeleteAsyncMainQueue() { + // swiftlint:disable:next function_body_length + func testFetchAll() { testLogin() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Delete installation1") - DispatchQueue.main.async { - guard let user = User.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } + guard var user = User.current else { + XCTFail("Should unwrap dates") + return + } - var userOnServer = user - userOnServer.updatedAt = user.updatedAt?.addingTimeInterval(+300) + user.updatedAt = user.updatedAt?.addingTimeInterval(+300) + user.customKey = "newValue" + let userOnServer = QueryResponse(results: [user], count: 1) - let encoded: Data! - do { - encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none) - //Get dates in correct format from ParseDecoding strategy - userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(user) + user = try user.getDecoder().decode(User.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - user.delete { result in - if case let .failure(error) = result { - XCTFail(error.localizedDescription) + do { + let fetched = try [user].fetchAll() + fetched.forEach { + switch $0 { + case .success(let fetched): + XCTAssert(fetched.hasSameObjectId(as: user)) + guard let fetchedCreatedAt = fetched.createdAt, + let fetchedUpdatedAt = fetched.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = user.createdAt, + let originalUpdatedAt = user.updatedAt, + let serverUpdatedAt = user.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) + XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(User.current?.customKey, user.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = User.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainUser: CurrentUserContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), + let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() } + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1], timeout: 20.0) } // swiftlint:disable:next function_body_length - func testFetchAll() { + func testFetchAllAsyncMainQueue() { testLogin() MockURLProtocol.removeAll() let expectation1 = XCTestExpectation(description: "Fetch user1") + guard var user = User.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + return + } - DispatchQueue.main.async { - guard var user = User.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } + user.updatedAt = user.updatedAt?.addingTimeInterval(+300) + user.customKey = "newValue" + let userOnServer = QueryResponse(results: [user], count: 1) - user.updatedAt = user.updatedAt?.addingTimeInterval(+300) - user.customKey = "newValue" - let userOnServer = QueryResponse(results: [user], count: 1) + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(user) + user = try user.getDecoder().decode(User.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(user) - user = try user.getDecoder().decode(User.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + [user].fetchAll { results in + switch results { - do { - let fetched = try [user].fetchAll() + case .success(let fetched): fetched.forEach { switch $0 { case .success(let fetched): @@ -1589,143 +1667,176 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() } wait(for: [expectation1], timeout: 20.0) } // swiftlint:disable:next function_body_length - func testFetchAllAsyncMainQueue() { + func testSaveAll() { testLogin() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Fetch user1") - DispatchQueue.main.async { - guard var user = User.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - return - } + guard var user = User.current else { + XCTFail("Should unwrap dates") + return + } - user.updatedAt = user.updatedAt?.addingTimeInterval(+300) - user.customKey = "newValue" - let userOnServer = QueryResponse(results: [user], count: 1) + user.updatedAt = user.updatedAt?.addingTimeInterval(+300) + user.customKey = "newValue" + let userOnServer = [BatchResponseItem(success: user, error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(user) - user = try user.getDecoder().decode(User.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(user) + user = try user.getDecoder().decode(User.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - [user].fetchAll { results in - switch results { + do { + let saved = try [user].saveAll() + saved.forEach { + switch $0 { + case .success(let saved): + XCTAssert(saved.hasSameObjectId(as: user)) + guard let savedCreatedAt = saved.createdAt, + let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return + } + guard let originalCreatedAt = user.createdAt, + let originalUpdatedAt = user.updatedAt, + let serverUpdatedAt = user.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(savedCreatedAt, originalCreatedAt) + XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(User.current?.customKey, user.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = User.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainUser: CurrentUserContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), + let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") + } + } + } catch { + XCTFail(error.localizedDescription) + } - case .success(let fetched): - fetched.forEach { - switch $0 { - case .success(let fetched): - XCTAssert(fetched.hasSameObjectId(as: user)) - guard let fetchedCreatedAt = fetched.createdAt, - let fetchedUpdatedAt = fetched.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = user.createdAt, - let originalUpdatedAt = user.updatedAt, - let serverUpdatedAt = user.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(fetchedCreatedAt, originalCreatedAt) - XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(User.current?.customKey, user.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = User.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation1.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainUser: CurrentUserContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), - let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } + do { + let saved = try [user].saveAll(transaction: true) + saved.forEach { + switch $0 { + case .success(let saved): + XCTAssert(saved.hasSameObjectId(as: user)) + guard let savedCreatedAt = saved.createdAt, + let savedUpdatedAt = saved.updatedAt else { + XCTFail("Should unwrap dates") + return } + guard let originalCreatedAt = user.createdAt, + let originalUpdatedAt = user.updatedAt, + let serverUpdatedAt = user.updatedAt else { + XCTFail("Should unwrap dates") + return + } + XCTAssertEqual(savedCreatedAt, originalCreatedAt) + XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) + XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) + XCTAssertEqual(User.current?.customKey, user.customKey) + + //Should be updated in memory + guard let updatedCurrentDate = User.current?.updatedAt else { + XCTFail("Should unwrap current date") + return + } + XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) + + #if !os(Linux) && !os(Android) + //Should be updated in Keychain + guard let keychainUser: CurrentUserContainer + = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), + let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { + XCTFail("Should get object from Keychain") + return + } + XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) + #endif case .failure(let error): XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() } + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1], timeout: 20.0) } // swiftlint:disable:next function_body_length - func testSaveAll() { + func testSaveAllAsyncMainQueue() { testLogin() MockURLProtocol.removeAll() let expectation1 = XCTestExpectation(description: "Save user1") let expectation2 = XCTestExpectation(description: "Save user2") - DispatchQueue.main.async { - guard var user = User.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - expectation2.fulfill() - return - } + guard var user = User.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + expectation2.fulfill() + return + } - user.updatedAt = user.updatedAt?.addingTimeInterval(+300) - user.customKey = "newValue" - let userOnServer = [BatchResponseItem(success: user, error: nil)] + user.updatedAt = user.updatedAt?.addingTimeInterval(+300) + user.customKey = "newValue" + let userOnServer = [BatchResponseItem(success: user, error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(user) - user = try user.getDecoder().decode(User.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + //Get dates in correct format from ParseDecoding strategy + let encoded1 = try ParseCoding.jsonEncoder().encode(user) + user = try user.getDecoder().decode(User.self, from: encoded1) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + expectation2.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - do { - let saved = try [user].saveAll() + [user].saveAll { results in + switch results { + + case .success(let saved): saved.forEach { switch $0 { case .success(let saved): @@ -1771,14 +1882,16 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation1.fulfill() + } - do { - let saved = try [user].saveAll(transaction: true) + [user].saveAll(transaction: true) { results in + switch results { + + case .success(let saved): saved.forEach { switch $0 { case .success(let saved): @@ -1824,286 +1937,120 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should have fetched: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have fetched: \(error.localizedDescription)") } - expectation2.fulfill() } wait(for: [expectation1, expectation2], timeout: 20.0) } - // swiftlint:disable:next function_body_length - func testSaveAllAsyncMainQueue() { + func testDeleteAll() { testLogin() MockURLProtocol.removeAll() - let expectation1 = XCTestExpectation(description: "Save user1") - let expectation2 = XCTestExpectation(description: "Save user2") - - DispatchQueue.main.async { - guard var user = User.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - expectation2.fulfill() - return - } - - user.updatedAt = user.updatedAt?.addingTimeInterval(+300) - user.customKey = "newValue" - let userOnServer = [BatchResponseItem(success: user, error: nil)] + guard let user = User.current else { + XCTFail("Should unwrap dates") + return + } - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - //Get dates in correct format from ParseDecoding strategy - let encoded1 = try ParseCoding.jsonEncoder().encode(user) - user = try user.getDecoder().decode(User.self, from: encoded1) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let userOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - [user].saveAll { results in - switch results { + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + } catch { + XCTFail("Should encode/decode. Error \(error)") + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - case .success(let saved): - saved.forEach { - switch $0 { - case .success(let saved): - XCTAssert(saved.hasSameObjectId(as: user)) - guard let savedCreatedAt = saved.createdAt, - let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - guard let originalCreatedAt = user.createdAt, - let originalUpdatedAt = user.updatedAt, - let serverUpdatedAt = user.updatedAt else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - return - } - XCTAssertEqual(savedCreatedAt, originalCreatedAt) - XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(User.current?.customKey, user.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = User.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation1.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainUser: CurrentUserContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), - let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation1.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") + do { + let deleted = try [user].deleteAll() + deleted.forEach { + if case let .failure(error) = $0 { + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation1.fulfill() } + } catch { + XCTFail(error.localizedDescription) + } - [user].saveAll(transaction: true) { results in - switch results { - - case .success(let saved): - saved.forEach { - switch $0 { - case .success(let saved): - XCTAssert(saved.hasSameObjectId(as: user)) - guard let savedCreatedAt = saved.createdAt, - let savedUpdatedAt = saved.updatedAt else { - XCTFail("Should unwrap dates") - expectation2.fulfill() - return - } - guard let originalCreatedAt = user.createdAt, - let originalUpdatedAt = user.updatedAt, - let serverUpdatedAt = user.updatedAt else { - XCTFail("Should unwrap dates") - expectation2.fulfill() - return - } - XCTAssertEqual(savedCreatedAt, originalCreatedAt) - XCTAssertEqual(savedUpdatedAt, originalUpdatedAt) - XCTAssertEqual(savedUpdatedAt, serverUpdatedAt) - XCTAssertEqual(User.current?.customKey, user.customKey) - - //Should be updated in memory - guard let updatedCurrentDate = User.current?.updatedAt else { - XCTFail("Should unwrap current date") - expectation2.fulfill() - return - } - XCTAssertEqual(updatedCurrentDate, serverUpdatedAt) - - #if !os(Linux) && !os(Android) - //Should be updated in Keychain - guard let keychainUser: CurrentUserContainer - = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser), - let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else { - XCTFail("Should get object from Keychain") - expectation2.fulfill() - return - } - XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt) - #endif - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have fetched: \(error.localizedDescription)") + do { + let deleted = try [user].deleteAll(transaction: true) + deleted.forEach { + if case let .failure(error) = $0 { + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation2.fulfill() } + } catch { + XCTFail(error.localizedDescription) } - wait(for: [expectation1, expectation2], timeout: 20.0) } - func testDeleteAll() { + func testDeleteAllAsyncMainQueue() { testLogin() MockURLProtocol.removeAll() let expectation1 = XCTestExpectation(description: "Delete user1") let expectation2 = XCTestExpectation(description: "Delete user2") - DispatchQueue.main.async { - guard let user = User.current else { - XCTFail("Should unwrap dates") - expectation1.fulfill() - expectation2.fulfill() - return - } + guard let user = User.current else { + XCTFail("Should unwrap") + expectation1.fulfill() + expectation2.fulfill() + return + } - let userOnServer = [BatchResponseItem(success: NoBody(), error: nil)] + let userOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } + let encoded: Data! + do { + encoded = try ParseCoding.jsonEncoder().encode(userOnServer) + } catch { + XCTFail("Should encode/decode. Error \(error)") + expectation1.fulfill() + expectation2.fulfill() + return + } + MockURLProtocol.mockRequests { _ in + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } - do { - let deleted = try [user].deleteAll() + [user].deleteAll { results in + switch results { + + case .success(let deleted): deleted.forEach { if case let .failure(error) = $0 { XCTFail("Should have deleted: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation1.fulfill() + } - do { - let deleted = try [user].deleteAll(transaction: true) + [user].deleteAll(transaction: true) { results in + switch results { + + case .success(let deleted): deleted.forEach { if case let .failure(error) = $0 { XCTFail("Should have deleted: \(error.localizedDescription)") } } - } catch { - XCTFail(error.localizedDescription) + case .failure(let error): + XCTFail("Should have deleted: \(error.localizedDescription)") } - expectation2.fulfill() } wait(for: [expectation1, expectation2], timeout: 20.0) } - func testDeleteAllAsyncMainQueue() { - testLogin() - MockURLProtocol.removeAll() - - let expectation1 = XCTestExpectation(description: "Delete user1") - let expectation2 = XCTestExpectation(description: "Delete user2") - - DispatchQueue.main.async { - guard let user = User.current else { - XCTFail("Should unwrap") - expectation1.fulfill() - expectation2.fulfill() - return - } - - let userOnServer = [BatchResponseItem(success: NoBody(), error: nil)] - - let encoded: Data! - do { - encoded = try ParseCoding.jsonEncoder().encode(userOnServer) - } catch { - XCTFail("Should encode/decode. Error \(error)") - expectation1.fulfill() - expectation2.fulfill() - return - } - MockURLProtocol.mockRequests { _ in - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } - - [user].deleteAll { results in - switch results { - - case .success(let deleted): - deleted.forEach { - if case let .failure(error) = $0 { - XCTFail("Should have deleted: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have deleted: \(error.localizedDescription)") - } - expectation1.fulfill() - } - - [user].deleteAll(transaction: true) { results in - switch results { - - case .success(let deleted): - deleted.forEach { - if case let .failure(error) = $0 { - XCTFail("Should have deleted: \(error.localizedDescription)") - } - } - case .failure(let error): - XCTFail("Should have deleted: \(error.localizedDescription)") - } - expectation2.fulfill() - } - } - wait(for: [expectation1, expectation2], timeout: 20.0) - } - func testMeCommand() { var user = User() user.objectId = "me"