diff --git a/CHANGELOG.md b/CHANGELOG.md index 14185bfda..f1b4b7f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ __New features__ * Add fetchAll method to array of Parse Pointer Object's ([#141](https://github.com/netreconlab/Parse-Swift/pull/141)), thanks to [Corey Baker](https://github.com/cbaker6). __Fixes__ -* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6). +* Improve mutiple types conformance to Equatable and Hashable ([#148](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6). +* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/148)), thanks to [Corey Baker](https://github.com/cbaker6). ### 5.8.2 [Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.1...5.8.2), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.8.2/documentation/parseswift) diff --git a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift index a5276d5d8..509dd8f26 100644 --- a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift @@ -165,7 +165,8 @@ score.save { result in } //: This will store the second batch score to be used later. -var score2ForFetchedLater: GameScore? +var scoreToFetchLater: GameScore? +var score2ToFetchLater: GameScore? //: Saving multiple GameScores at once with batching. [score, score2].saveAll { results in @@ -179,8 +180,10 @@ var score2ForFetchedLater: GameScore? Saved \"\(savedScore.className)\" with points \(String(describing: savedScore.points)) successfully """) - if index == 1 { - score2ForFetchedLater = savedScore + if index == 0 { + scoreToFetchLater = savedScore + } else if index == 1 { + score2ToFetchLater = savedScore } index += 1 case .failure(let error): @@ -203,8 +206,10 @@ var score2ForFetchedLater: GameScore? switch otherResult { case .success(let savedScore): print("Saved \"\(savedScore.className)\" with points \(savedScore.points) successfully") - if index == 1 { - score2ForFetchedLater = savedScore + if index == 0 { + scoreToFetchLater = savedScore + } else if index == 1 { + score2ToFetchLater = savedScore } index += 1 case .failure(let error): @@ -299,7 +304,7 @@ Task { } //: Now we will fetch a ParseObject that has already been saved based on its' objectId. -let scoreToFetch = GameScore(objectId: score2ForFetchedLater?.objectId) +let scoreToFetch = GameScore(objectId: scoreToFetchLater?.objectId) //: Asynchronous completion block fetch this GameScore based on it is objectId alone. scoreToFetch.fetch { result in @@ -322,7 +327,7 @@ Task { } //: Now we will fetch `ParseObject`'s in batch that have already been saved based on its' objectId. -let score2ToFetch = GameScore(objectId: score2ForFetchedLater?.objectId) +let score2ToFetch = GameScore(objectId: score2ToFetchLater?.objectId) //: Asynchronous completion block fetch GameScores based on it is objectId alone. [scoreToFetch, score2ToFetch].fetchAll { result in diff --git a/ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift index b61565899..13b8e1bb3 100644 --- a/ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift @@ -12,14 +12,6 @@ import ParseSwift PlaygroundPage.current.needsIndefiniteExecution = true -Task { - do { - try await initializeParse() - } catch { - assertionFailure("Error initializing Parse-Swift: \(error)") - } -} - struct User: ParseUser { //: These are required by `ParseObject`. var objectId: String? @@ -52,6 +44,19 @@ struct User: ParseUser { } } +Task { + do { + try await initializeParse() + } catch { + assertionFailure("Error initializing Parse-Swift: \(error)") + } + do { + try await User.logout() + } catch let error { + print("Error logging out: \(error)") + } +} + /*: Sign up user asynchronously - Performs work on background queue and returns to specified callbackQueue. diff --git a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift index c236066cf..0e42e52c5 100644 --- a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift @@ -182,8 +182,8 @@ Task { let currentUser = try? await User.current() currentUser?.fetch(includeKeys: ["gameScore"]) { result in switch result { - case .success: - print("Successfully fetched user with gameScore key: \(String(describing: User.current))") + case .success(let user): + print("Successfully fetched user with gameScore key: \(user)") case .failure(let error): print("Error fetching User: \(error)") } @@ -196,8 +196,8 @@ Task { let currentUser = try? await User.current() currentUser?.fetch(includeKeys: ["*"]) { result in switch result { - case .success: - print("Successfully fetched user with all keys: \(String(describing: User.current))") + case .success(let user): + print("Successfully fetched user with all keys: \(user)") case .failure(let error): print("Error fetching User: \(error)") } diff --git a/Sources/ParseSwift/API/API+Command.swift b/Sources/ParseSwift/API/API+Command.swift index f8c0c8184..8969a3dfa 100644 --- a/Sources/ParseSwift/API/API+Command.swift +++ b/Sources/ParseSwift/API/API+Command.swift @@ -57,7 +57,9 @@ internal extension API { uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil, stream: InputStream, completion: @escaping (ParseError?) -> Void) { - guard method == .POST || method == .PUT || method == .PATCH else { + guard method == .POST || + method == .PUT || + method == .PATCH else { callbackQueue.async { completion(nil) } @@ -133,7 +135,9 @@ internal extension API { } } else { // ParseFiles are handled with a dedicated URLSession - if method == .POST || method == .PUT || method == .PATCH { + if method == .POST || + method == .PUT || + method == .PATCH { switch await self.prepareURLRequest(options: options, batching: batching, childObjects: childObjects, @@ -258,7 +262,8 @@ internal extension API { Task { do { var headers = try await API.getHeaders(options: options) - if method == .GET || method == .DELETE { + if method == .GET || + method == .DELETE { headers.removeValue(forKey: "X-Parse-Request-Id") } let url = parseURL == nil ? @@ -405,8 +410,9 @@ internal extension API.Command { original data: Data?, ignoringCustomObjectIdConfig: Bool, batching: Bool = false) async throws -> API.Command where V: ParseObject { - if Parse.configuration.isRequiringCustomObjectIds - && object.objectId == nil && !ignoringCustomObjectIdConfig { + if Parse.configuration.isRequiringCustomObjectIds && + object.objectId == nil && + !ignoringCustomObjectIdConfig { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") } if try await object.isSaved() { diff --git a/Sources/ParseSwift/API/API+NonParseBodyCommand.swift b/Sources/ParseSwift/API/API+NonParseBodyCommand.swift index 8a87cb378..0744b8c1b 100644 --- a/Sources/ParseSwift/API/API+NonParseBodyCommand.swift +++ b/Sources/ParseSwift/API/API+NonParseBodyCommand.swift @@ -67,7 +67,8 @@ internal extension API { let params = self.params?.getURLQueryItems() do { var headers = try await API.getHeaders(options: options) - if method == .GET || method == .DELETE { + if method == .GET || + method == .DELETE { headers.removeValue(forKey: "X-Parse-Request-Id") } let url = API.serverURL(options: options).appendingPathComponent(path.urlComponent) diff --git a/Sources/ParseSwift/API/API.swift b/Sources/ParseSwift/API/API.swift index f9ed2248b..0caf8882b 100644 --- a/Sources/ParseSwift/API/API.swift +++ b/Sources/ParseSwift/API/API.swift @@ -203,8 +203,22 @@ public struct API { } } + // swiftlint:disable:next cyclomatic_complexity public static func == (lhs: API.Option, rhs: API.Option) -> Bool { - lhs.hashValue == rhs.hashValue + switch (lhs, rhs) { + case (.usePrimaryKey, .usePrimaryKey): return true + case (.removeMimeType, .removeMimeType): return true + case (.sessionToken(let object1), .sessionToken(let object2)): return object1 == object2 + case (.installationId(let object1), .installationId(let object2)): return object1 == object2 + case (.mimeType(let object1), .mimeType(let object2)): return object1 == object2 + case (.fileSize(let object1), .fileSize(let object2)): return object1 == object2 + case (.metadata(let object1), .metadata(let object2)): return object1 == object2 + case (.tags(let object1), .tags(let object2)): return object1 == object2 + case (.context(let object1), .context(let object2)): return object1.isEqual(object2) + case (.cachePolicy(let object1), .cachePolicy(let object2)): return object1 == object2 + case (.serverURL(let object1), .serverURL(let object2)): return object1 == object2 + default: return false + } } } @@ -228,7 +242,7 @@ public struct API { headers["X-Parse-Client-Version"] = clientVersion() headers["X-Parse-Request-Id"] = Self.createUniqueRequestId() - options.forEach { (option) in + options.forEach { option in switch option { case .usePrimaryKey: headers["X-Parse-Master-Key"] = Parse.configuration.primaryKey @@ -272,11 +286,22 @@ public struct API { } internal static func serverURL(options: API.Options) -> URL { - guard let differentServerURLOption = options.first(where: { $0 == .serverURL("") }), - case .serverURL(let differentServerURLString) = differentServerURLOption, - let differentURL = URL(string: differentServerURLString) else { + var optionURL: URL? + // BAKER: Currently have to step through all options and + // break to get the current URL. + for option in options { + switch option { + case .serverURL(let url): + optionURL = URL(string: url) + default: + continue + } + break + } + + guard let currentURL = optionURL else { return Parse.configuration.serverURL } - return differentURL + return currentURL } } diff --git a/Sources/ParseSwift/Coding/AnyCodable.swift b/Sources/ParseSwift/Coding/AnyCodable.swift index 2c0e3efc3..a25f13432 100755 --- a/Sources/ParseSwift/Coding/AnyCodable.swift +++ b/Sources/ParseSwift/Coding/AnyCodable.swift @@ -110,5 +110,6 @@ extension AnyCodable: ExpressibleByBooleanLiteral {} extension AnyCodable: ExpressibleByIntegerLiteral {} extension AnyCodable: ExpressibleByFloatLiteral {} extension AnyCodable: ExpressibleByStringLiteral {} +extension AnyCodable: ExpressibleByStringInterpolation {} extension AnyCodable: ExpressibleByArrayLiteral {} extension AnyCodable: ExpressibleByDictionaryLiteral {} diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index aac2d6419..38cb94b46 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -367,7 +367,8 @@ internal class _ParseEncoder: JSONEncoder, Encoder { } valueToEncode = pointer } else if let object = value as? Objectable { - if !batching || (batching && codingPath.last?.stringValue == "body"), + if !batching || + (batching && codingPath.last?.stringValue == "body"), let pointer = try? PointerType(object) { if let uniquePointer = self.uniquePointer, uniquePointer.hasSameObjectId(as: pointer) { @@ -507,8 +508,8 @@ private struct _ParseEncoderKeyedEncodingContainer: KeyedEncodin guard !shouldSkipKey(key) else { return } var valueToEncode: Encodable = value - if ((value as? Objectable) != nil) - || ((value as? ParsePointer) != nil) { + if ((value as? Objectable) != nil) || + ((value as? ParsePointer) != nil) { if let replacedObject = try self.encoder.deepFindAndReplaceParseObjects(value) { valueToEncode = replacedObject } @@ -964,18 +965,22 @@ extension _ParseEncoder { // Disambiguation between variable and function is required due to // issue tracked at: https://bugs.swift.org/browse/SR-1846 let type = Swift.type(of: value) - if type == Date.self || type == NSDate.self { + if type == Date.self || + type == NSDate.self { // Respect Date encoding strategy return try self.box((value as! Date)) - } else if type == Data.self || type == NSData.self { + } else if type == Data.self || + type == NSData.self { // Respect Data encoding strategy // swiftlint:disable:next force_cast return try self.box((value as! Data)) - } else if type == URL.self || type == NSURL.self { + } else if type == URL.self || + type == NSURL.self { // Encode URLs as single strings. // swiftlint:disable:next force_cast return self.box((value as! URL).absoluteString) - } else if type == Decimal.self || type == NSDecimalNumber.self { + } else if type == Decimal.self || + type == NSDecimalNumber.self { // JSONSerialization can natively handle NSDecimalNumber. // swiftlint:disable:next force_cast return (value as! NSDecimalNumber) diff --git a/Sources/ParseSwift/Extensions/Encodable.swift b/Sources/ParseSwift/Extensions/Encodable.swift index cfee3b51d..d3e53062b 100644 --- a/Sources/ParseSwift/Extensions/Encodable.swift +++ b/Sources/ParseSwift/Extensions/Encodable.swift @@ -10,14 +10,25 @@ import Foundation internal extension Encodable { func isEqual(_ other: Encodable?) -> Bool { - guard let lhsData = try? ParseCoding.parseEncoder().encode(self, - acl: nil), + guard let lhsData = try? ParseCoding + .parseEncoder() + .encode( + self, + acl: nil + ), let lhsString = String(data: lhsData, encoding: .utf8), let other = other, - let rhsData = try? ParseCoding.parseEncoder().encode(other, - acl: nil), - let rhsString = String(data: rhsData, encoding: .utf8) else { - return false + let rhsData = try? ParseCoding + .parseEncoder() + .encode( + other, + acl: nil + ), + let rhsString = String( + data: rhsData, + encoding: .utf8 + ) else { + return false } return lhsString == rhsString } diff --git a/Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift b/Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift index 7dbed0b3c..dcd99be38 100644 --- a/Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift +++ b/Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift @@ -45,11 +45,11 @@ public enum Event: Equatable { public static func == (lhs: Event, rhs: Event) -> Bool { switch (lhs, rhs) { - case (.entered(let obj1), .entered(let obj2)): return obj1 == obj2 - case (.left(let obj1), .left(let obj2)): return obj1 == obj2 - case (.created(let obj1), .created(let obj2)): return obj1 == obj2 - case (.updated(let obj1), .updated(let obj2)): return obj1 == obj2 - case (.deleted(let obj1), .deleted(let obj2)): return obj1 == obj2 + case (.entered(let object1), .entered(let object2)): return object1 == object2 + case (.left(let object1), .left(let object2)): return object1 == object2 + case (.created(let object1), .created(let object2)): return object1 == object2 + case (.updated(let object1), .updated(let object2)): return object1 == object2 + case (.deleted(let object1), .deleted(let object2)): return object1 == object2 default: return false } } diff --git a/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift b/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift index 0a69b7aa3..b1bb856f2 100644 --- a/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift +++ b/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift @@ -631,7 +631,8 @@ extension ParseLiveQuery { if isUserWantsToConnect { self.isDisconnectedByUser = false } - if self.status == .connected || self.isDisconnectedByUser { + if self.status == .connected || + self.isDisconnectedByUser { completion(nil) return } @@ -769,8 +770,8 @@ extension ParseLiveQuery { } static func == (lhs: SubscriptionRecord, rhs: SubscriptionRecord) -> Bool { - lhs.messageData == rhs.messageData - && lhs.queryData == rhs.queryData + lhs.messageData == rhs.messageData && + lhs.queryData == rhs.queryData } } } diff --git a/Sources/ParseSwift/Objects/ParseInstallation.swift b/Sources/ParseSwift/Objects/ParseInstallation.swift index 634c8a646..00a95cd43 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation.swift @@ -174,7 +174,8 @@ extension ParseInstallation { func endpoint(_ method: API.Method) async throws -> API.Endpoint { try await yieldIfNotInitialized() - if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || + method != .POST { return endpoint } else { return .installations diff --git a/Sources/ParseSwift/Objects/ParseObject+async.swift b/Sources/ParseSwift/Objects/ParseObject+async.swift index c8887f70d..741e3b90d 100644 --- a/Sources/ParseSwift/Objects/ParseObject+async.swift +++ b/Sources/ParseSwift/Objects/ParseObject+async.swift @@ -312,7 +312,8 @@ internal extension ParseObject { objectsSavedBeforeThisOne: nil, filesSavedBeforeThisOne: nil) var waitingToBeSaved = object.unsavedChildren - if isShouldReturnIfChildObjectsFound && waitingToBeSaved.count > 0 { + if isShouldReturnIfChildObjectsFound && + waitingToBeSaved.count > 0 { let error = ParseError(code: .otherCause, message: """ When using transactions, all child ParseObjects have to originally @@ -349,7 +350,9 @@ or disable transactions for this call. } } waitingToBeSaved = nextBatch - if waitingToBeSaved.count > 0 && savableObjects.count == 0 && savableFiles.count == 0 { + if waitingToBeSaved.count > 0 && + savableObjects.count == 0 && + savableFiles.count == 0 { throw ParseError(code: .otherCause, message: "Found a circular dependency in ParseObject.") } diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 040fe81a5..9eb742c5c 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -111,7 +111,7 @@ public protocol ParseObject: ParseTypeable, by comparing it to another `ParseObject`. - parameter keyPath: The `KeyPath` to check. - parameter original: The original `ParseObject`. - - returns: Returns a **true** if the keyPath should be restored or **false** otherwise. + - returns: Returns **true** if the keyPath should be restored or **false** otherwise. */ func shouldRestoreKey(_ keyPath: KeyPath, original: Self) -> Bool where W: Equatable @@ -200,7 +200,9 @@ public extension ParseObject { } func hasSameObjectId(as other: T) -> Bool { - other.className == className && other.objectId == objectId && objectId != nil + other.className == className && + other.objectId == objectId && + objectId != nil } func toPointer() throws -> Pointer { @@ -209,7 +211,8 @@ public extension ParseObject { func shouldRestoreKey(_ keyPath: KeyPath, original: Self) -> Bool where W: Equatable { - self[keyPath: keyPath] == nil && original[keyPath: keyPath] != self[keyPath: keyPath] + self[keyPath: keyPath] == nil && + original[keyPath: keyPath] != self[keyPath: keyPath] } func mergeParse(with object: Self) throws -> Self { @@ -246,6 +249,8 @@ extension ParseObject { public extension ParseObject { func hash(into hasher: inout Hasher) { hasher.combine(self.id) + hasher.combine(createdAt) + hasher.combine(updatedAt) } } diff --git a/Sources/ParseSwift/Objects/ParseRole.swift b/Sources/ParseSwift/Objects/ParseRole.swift index f7e56c8a3..fd91a62af 100644 --- a/Sources/ParseSwift/Objects/ParseRole.swift +++ b/Sources/ParseSwift/Objects/ParseRole.swift @@ -107,6 +107,8 @@ public extension ParseRole { func hash(into hasher: inout Hasher) { let name = self.name ?? self.objectId hasher.combine(name) + hasher.combine(createdAt) + hasher.combine(updatedAt) } func mergeParse(with object: Self) throws -> Self { diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index c8950ac01..36588f118 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -106,7 +106,8 @@ extension ParseUser { func endpoint(_ method: API.Method) async throws -> API.Endpoint { try await yieldIfNotInitialized() - if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || + method != .POST { return endpoint } else { return .users @@ -485,7 +486,8 @@ extension ParseUser { if let current = try? await Self.current() { let isAnonymous = await self.anonymous.isLinked() - if !current.hasSameObjectId(as: user) && isAnonymous { + if !current.hasSameObjectId(as: user) && + isAnonymous { await Self.deleteCurrentContainerFromStorage() } } @@ -1182,7 +1184,9 @@ extension ParseUser { func saveCommand(ignoringCustomObjectIdConfig: Bool = false) async throws -> API.Command { try await yieldIfNotInitialized() - if Parse.configuration.isRequiringCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig { + if Parse.configuration.isRequiringCustomObjectIds && + objectId == nil && + !ignoringCustomObjectIdConfig { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") } if try await isSaved() { diff --git a/Sources/ParseSwift/Protocols/Fileable.swift b/Sources/ParseSwift/Protocols/Fileable.swift index b68a1a2b8..156fdb3d8 100644 --- a/Sources/ParseSwift/Protocols/Fileable.swift +++ b/Sources/ParseSwift/Protocols/Fileable.swift @@ -19,14 +19,6 @@ extension Fileable { return url != nil } - mutating func hash(into hasher: inout Hasher) { - if let url = url { - hasher.combine(url) - } else { - hasher.combine(self.id) - } - } - public static func == (lhs: Self, rhs: Self) -> Bool { guard let lURL = lhs.url, let rURL = rhs.url else { diff --git a/Sources/ParseSwift/Protocols/Objectable.swift b/Sources/ParseSwift/Protocols/Objectable.swift index 1166a80ee..854380692 100644 --- a/Sources/ParseSwift/Protocols/Objectable.swift +++ b/Sources/ParseSwift/Protocols/Objectable.swift @@ -80,13 +80,15 @@ public extension Objectable { if !Parse.configuration.isRequiringCustomObjectIds { return objectId != nil } else { - return objectId != nil && createdAt != nil + return objectId != nil && + createdAt != nil } } func endpoint(_ method: API.Method) async throws -> API.Endpoint { try await yieldIfNotInitialized() - if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || + method != .POST { return endpoint } else { return .objects(className: className) @@ -107,14 +109,15 @@ extension Objectable { return hashString } + // BAKER: mark this internal. /// Specifies if a `ParseObject` has been saved. /// - warning: This will not be available in ParseSwift 6.0.0. Use `isSaved()` instead. - /// BAKER mark this internal. public var isSaved: Bool { if !Parse.configuration.isRequiringCustomObjectIds { return objectId != nil } else { - return objectId != nil && createdAt != nil + return objectId != nil && + createdAt != nil } } diff --git a/Sources/ParseSwift/Protocols/ParsePointerable.swift b/Sources/ParseSwift/Protocols/ParsePointerable.swift index 6edcdd6e6..26b8c8830 100644 --- a/Sources/ParseSwift/Protocols/ParsePointerable.swift +++ b/Sources/ParseSwift/Protocols/ParsePointerable.swift @@ -21,10 +21,11 @@ extension ParsePointer { /** Determines if two objects have the same objectId. - parameter as: Object to compare. - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. + - returns: Returns **true** if the other object has the same `objectId` or **false** if unsuccessful. */ func hasSameObjectId(as other: any ParsePointer) -> Bool { - return other.className == className && other.objectId == objectId + return other.className == className && + other.objectId == objectId } } @@ -47,19 +48,21 @@ extension ParsePointerObject { /** Determines if a `ParseObject` and `Pointer`have the same `objectId`. - parameter as: `ParseObject` to compare. - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. + - returns: Returns **true** if the other object has the same `objectId` or **false** if unsuccessful. */ func hasSameObjectId(as other: Object) -> Bool { - return other.className == className && other.objectId == objectId + return other.className == className && + other.objectId == objectId } /** Determines if two `Pointer`'s have the same `objectId`. - parameter as: `Pointer` to compare. - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. + - returns: Returns **true** if the other object has the same `objectId` or **false** if unsuccessful. */ func hasSameObjectId(as other: Self) -> Bool { - return other.className == className && other.objectId == objectId + return other.className == className && + other.objectId == objectId } /** diff --git a/Sources/ParseSwift/Storage/KeychainStore.swift b/Sources/ParseSwift/Storage/KeychainStore.swift index fdbde340d..da1c08442 100644 --- a/Sources/ParseSwift/Storage/KeychainStore.swift +++ b/Sources/ParseSwift/Storage/KeychainStore.swift @@ -306,7 +306,11 @@ actor KeychainStore: SecureStorable { mutatedKeychainAccessGroup.accessGroup = nil let removedNoAccessGroupObject = self.removeObject(forKey: key, accessGroup: mutatedKeychainAccessGroup) - if !(removedDefaultObject || removedToggledObject || removedNoAccessGroupObject) { + if !( + removedDefaultObject || + removedToggledObject || + removedNoAccessGroupObject + ) { return false } } diff --git a/Sources/ParseSwift/Types/ParseCLP.swift b/Sources/ParseSwift/Types/ParseCLP.swift index cb46ebb00..6b38e7c98 100644 --- a/Sources/ParseSwift/Types/ParseCLP.swift +++ b/Sources/ParseSwift/Types/ParseCLP.swift @@ -353,11 +353,12 @@ public extension ParseCLP { public extension ParseCLP { internal func hasWriteAccess(_ entity: String, check addField: Bool) -> Bool { - let access = hasAccess(.create, for: entity) - && hasAccess(.update, for: entity) - && hasAccess(.delete, for: entity) + let access = hasAccess(.create, for: entity) && + hasAccess(.update, for: entity) && + hasAccess(.delete, for: entity) if addField { - return access && hasAccess(.addField, for: entity) + return access && + hasAccess(.addField, for: entity) } return access } @@ -568,9 +569,9 @@ public extension ParseCLP { have access if they are apart of a `ParseRole` that has access. */ func hasReadAccess(_ objectId: String) -> Bool { - hasAccess(.get, for: objectId) - && hasAccess(.find, for: objectId) - && hasAccess(.count, for: objectId) + hasAccess(.get, for: objectId) && + hasAccess(.find, for: objectId) && + hasAccess(.count, for: objectId) } /** diff --git a/Sources/ParseSwift/Types/ParseError.swift b/Sources/ParseSwift/Types/ParseError.swift index 63ab04ea8..93e3789e6 100644 --- a/Sources/ParseSwift/Types/ParseError.swift +++ b/Sources/ParseSwift/Types/ParseError.swift @@ -546,6 +546,7 @@ extension ParseError: Equatable { lhs.code == rhs.code && lhs.message == rhs.message && lhs.error == rhs.error && + lhs.otherCode == rhs.otherCode && lhs.swift?.localizedDescription == rhs.swift?.localizedDescription } } diff --git a/Sources/ParseSwift/Types/ParseOperation.swift b/Sources/ParseSwift/Types/ParseOperation.swift index b164a5f9d..1a375911a 100644 --- a/Sources/ParseSwift/Types/ParseOperation.swift +++ b/Sources/ParseSwift/Types/ParseOperation.swift @@ -77,7 +77,8 @@ public struct ParseOperation: Savable, public func set(_ key: (String, WritableKeyPath), to value: W?) -> Self where W: Codable & Equatable { var mutableOperation = self - if value == nil && target[keyPath: key.1] != nil { + if value == nil && + target[keyPath: key.1] != nil { mutableOperation.keysToNull.insert(key.0) mutableOperation.target[keyPath: key.1] = value } else if target[keyPath: key.1] != value { diff --git a/Sources/ParseSwift/Types/ParsePush.swift b/Sources/ParseSwift/Types/ParsePush.swift index ac83f4620..d9bf97860 100644 --- a/Sources/ParseSwift/Types/ParsePush.swift +++ b/Sources/ParseSwift/Types/ParsePush.swift @@ -174,7 +174,8 @@ extension ParsePush { public func send(options: API.Options = [], callbackQueue: DispatchQueue = .main, completion: @escaping (Result) -> Void) { - if expirationTime != nil && expirationInterval != nil { + if expirationTime != nil && + expirationInterval != nil { let error = ParseError(code: .otherCause, message: "expirationTime and expirationInterval cannot both be set.") callbackQueue.async { @@ -182,7 +183,8 @@ extension ParsePush { } return } - if `where` != nil && channels != nil { + if `where` != nil && + channels != nil { let error = ParseError(code: .otherCause, message: "query and channels cannot both be set.") callbackQueue.async { diff --git a/Sources/ParseSwift/Types/ParseServer+combine.swift b/Sources/ParseSwift/Types/ParseServer+combine.swift index 08951b19e..de27d9f1c 100644 --- a/Sources/ParseSwift/Types/ParseServer+combine.swift +++ b/Sources/ParseSwift/Types/ParseServer+combine.swift @@ -25,7 +25,8 @@ public extension ParseServer { switch result { case .success(let status): subject.send(status) - if status == .ok || status == .error { + if status == .ok || + status == .error { subject.send(completion: .finished) } case .failure(let error): diff --git a/Sources/ParseSwift/Types/ParseVersion.swift b/Sources/ParseSwift/Types/ParseVersion.swift index 8f65d2478..d543161ff 100644 --- a/Sources/ParseSwift/Types/ParseVersion.swift +++ b/Sources/ParseSwift/Types/ParseVersion.swift @@ -84,11 +84,13 @@ public struct ParseVersion: ParseTypeable, Hashable { case alpha, beta static func < (lhs: ParseVersion.PrereleaseName, rhs: ParseVersion.PrereleaseName) -> Bool { - lhs == .alpha && rhs == .beta + lhs == .alpha && + rhs == .beta } static func > (lhs: ParseVersion.PrereleaseName, rhs: ParseVersion.PrereleaseName) -> Bool { - lhs == .beta && rhs == .alpha + lhs == .beta && + rhs == .alpha } } @@ -104,7 +106,10 @@ public struct ParseVersion: ParseTypeable, Hashable { patch: Int, prereleaseName: PrereleaseName?, prereleaseVersion: Int?) throws { - if prereleaseName != nil && prereleaseVersion == nil || prereleaseName == nil && prereleaseVersion != nil { + if prereleaseName != nil && + prereleaseVersion == nil || + prereleaseName == nil && + prereleaseVersion != nil { throw ParseError(code: .otherCause, // swiftlint:disable:next line_length message: "preleaseName and prereleaseVersion are both required, you cannot have one without the other") @@ -203,9 +208,11 @@ extension ParseVersion: Comparable { return true } else if left.patch < right.patch { return false - } else if left.prereleaseVersion == nil && right.prereleaseVersion != nil { + } else if left.prereleaseVersion == nil && + right.prereleaseVersion != nil { return true - } else if left.prereleaseVersion != nil && right.prereleaseVersion == nil { + } else if left.prereleaseVersion != nil && + right.prereleaseVersion == nil { return false } else if let leftPreReleaseName = left.prereleaseName, let rightPreReleaseName = right.prereleaseName, @@ -226,7 +233,8 @@ extension ParseVersion: Comparable { } public static func >= (left: Self, right: Self) -> Bool { - guard left == right || left > right else { + guard left == right || + left > right else { return false } return true @@ -246,9 +254,11 @@ extension ParseVersion: Comparable { return true } else if left.patch > right.patch { return false - } else if left.prereleaseVersion != nil && right.prereleaseVersion == nil { + } else if left.prereleaseVersion != nil && + right.prereleaseVersion == nil { return true - } else if left.prereleaseVersion == nil && right.prereleaseVersion != nil { + } else if left.prereleaseVersion == nil && + right.prereleaseVersion != nil { return false } else if let leftPreReleaseName = left.prereleaseName, let rightPreReleaseName = right.prereleaseName, @@ -269,7 +279,8 @@ extension ParseVersion: Comparable { } public static func <= (left: Self, right: Self) -> Bool { - guard left == right || left < right else { + guard left == right || + left < right else { return false } return true diff --git a/Sources/ParseSwift/Types/Query.swift b/Sources/ParseSwift/Types/Query.swift index 7301d5557..eaba88c44 100644 --- a/Sources/ParseSwift/Types/Query.swift +++ b/Sources/ParseSwift/Types/Query.swift @@ -569,7 +569,9 @@ extension Query: Queryable { } return } - if order != nil || skip > 0 || self.limit != 100 { + if order != nil || + skip > 0 || + self.limit != 100 { let error = ParseError(code: .otherCause, message: "Cannot iterate on a query with sort, skip, or limit.") callbackQueue.async { diff --git a/Tests/ParseSwiftTests/APICommandTests.swift b/Tests/ParseSwiftTests/APICommandTests.swift index 62c91b7b2..ce03ee2ba 100644 --- a/Tests/ParseSwiftTests/APICommandTests.swift +++ b/Tests/ParseSwiftTests/APICommandTests.swift @@ -140,14 +140,67 @@ class APICommandTests: XCTestCase { XCTAssertEqual(API.Endpoint.schemas.urlComponent, "/schemas") } - func testOptionCacheHasher() throws { + func testOptionHasherEquatable() throws { var options = API.Options() - options.insert(.cachePolicy(.returnCacheDataDontLoad)) + let first = "first" + let second = "second" + let firstDictionary = [first: second] + let secondDictionary = [second: first] + let firstServerURLString = "http://parse:1337/\(first)" + let secondServerURLString = "http://parse:1337/\(second)" + XCTAssertFalse(options.contains(.usePrimaryKey)) - XCTAssertTrue(options.contains(.cachePolicy(.returnCacheDataDontLoad))) - XCTAssertTrue(options.contains(.cachePolicy(.reloadRevalidatingCacheData))) options.insert(.usePrimaryKey) XCTAssertTrue(options.contains(.usePrimaryKey)) + + XCTAssertFalse(options.contains(.removeMimeType)) + options.insert(.removeMimeType) + XCTAssertTrue(options.contains(.removeMimeType)) + + XCTAssertFalse(options.contains(.sessionToken(first))) + options.insert(.sessionToken(first)) + XCTAssertTrue(options.contains(.sessionToken(first))) + XCTAssertFalse(options.contains(.sessionToken(second))) + + XCTAssertFalse(options.contains(.installationId(first))) + options.insert(.installationId(first)) + XCTAssertTrue(options.contains(.installationId(first))) + XCTAssertFalse(options.contains(.installationId(second))) + + XCTAssertFalse(options.contains(.mimeType(first))) + options.insert(.mimeType(first)) + XCTAssertTrue(options.contains(.mimeType(first))) + XCTAssertFalse(options.contains(.mimeType(second))) + + XCTAssertFalse(options.contains(.fileSize(first))) + options.insert(.fileSize(first)) + XCTAssertTrue(options.contains(.fileSize(first))) + XCTAssertFalse(options.contains(.fileSize(second))) + + XCTAssertFalse(options.contains(.metadata(firstDictionary))) + options.insert(.metadata(firstDictionary)) + XCTAssertTrue(options.contains(.metadata(firstDictionary))) + XCTAssertFalse(options.contains(.metadata(secondDictionary))) + + XCTAssertFalse(options.contains(.tags(firstDictionary))) + options.insert(.tags(firstDictionary)) + XCTAssertTrue(options.contains(.tags(firstDictionary))) + XCTAssertFalse(options.contains(.tags(secondDictionary))) + + XCTAssertFalse(options.contains(.context(first))) + options.insert(.context(first)) + XCTAssertTrue(options.contains(.context(first))) + XCTAssertFalse(options.contains(.context(second))) + + XCTAssertFalse(options.contains(.cachePolicy(.returnCacheDataDontLoad))) + options.insert(.cachePolicy(.returnCacheDataDontLoad)) + XCTAssertTrue(options.contains(.cachePolicy(.returnCacheDataDontLoad))) + XCTAssertFalse(options.contains(.cachePolicy(.reloadRevalidatingCacheData))) + + XCTAssertFalse(options.contains(.serverURL(firstServerURLString))) + options.insert(.serverURL(firstServerURLString)) + XCTAssertTrue(options.contains(.serverURL(firstServerURLString))) + XCTAssertFalse(options.contains(.serverURL(secondServerURLString))) } func testExecuteCorrectly() async { @@ -199,7 +252,7 @@ class APICommandTests: XCTestCase { XCTFail("Should have thrown an error") } catch { guard let error = error as? ParseError else { - XCTFail("should be able unwrap final error to ParseError") + XCTFail("Should be able unwrap final error to ParseError") return } XCTAssertEqual(originalError.code, error.code) @@ -240,7 +293,7 @@ class APICommandTests: XCTestCase { XCTFail("Should have thrown an error") } catch { guard let error = error as? ParseError else { - XCTFail("should be able unwrap final error to ParseError") + XCTFail("Should be able unwrap final error to ParseError") return } XCTAssertEqual(error.code, parseError.code) @@ -263,7 +316,7 @@ class APICommandTests: XCTestCase { XCTFail("Should have thrown an error") } catch { guard let error = error as? ParseError else { - XCTFail("should be able unwrap final error to ParseError") + XCTFail("Should be able unwrap final error to ParseError") return } XCTAssertEqual(originalError.code, error.code) @@ -304,7 +357,7 @@ class APICommandTests: XCTestCase { XCTFail("Should have thrown an error") } catch { guard let error = error as? ParseError else { - XCTFail("should be able unwrap final error to ParseError") + XCTFail("Should be able unwrap final error to ParseError") return } XCTAssertEqual(error.code, parseError.code) @@ -329,7 +382,7 @@ class APICommandTests: XCTestCase { XCTFail("Should have thrown an error") } catch { guard let error = error as? ParseError else { - XCTFail("should be able unwrap final error to ParseError") + XCTFail("Should be able unwrap final error to ParseError") return } XCTAssertEqual(originalError.code, error.code) diff --git a/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift b/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift index ed71059a2..581d4c572 100755 --- a/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift +++ b/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift @@ -66,11 +66,13 @@ class AnyCodableTests: XCTestCase { bool: true, hasUnderscore: "another string")) + let injectedValue = 1234 let dictionary: [String: AnyCodable] = [ "boolean": true, "integer": 42, "double": 3.14159265358979323846, "string": "string", + "stringInterpolation": "string \(injectedValue)", "array": [1, 2, 3], "nested": [ "a": "alpha", @@ -94,6 +96,7 @@ class AnyCodableTests: XCTestCase { "integer": 42, "double": 3.14159265358979323846, "string": "string", + "stringInterpolation": "string 1234", "array": [1, 2, 3], "nested": { "a": "alpha", diff --git a/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift b/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift index 6f608c322..9136367dc 100755 --- a/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift +++ b/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift @@ -29,11 +29,13 @@ class AnyEncodableTests: XCTestCase { bool: true, hasUnderscore: "another string")) + let injectedValue = 1234 let dictionary: [String: AnyEncodable] = [ "boolean": true, "integer": 42, "double": 3.14159265358979323846, "string": "string", + "stringInterpolation": "string \(injectedValue)", "array": [1, 2, 3], "nested": [ "a": "alpha", @@ -58,6 +60,7 @@ class AnyEncodableTests: XCTestCase { "integer": 42, "double": 3.14159265358979323846, "string": "string", + "stringInterpolation": "string 1234", "array": [1, 2, 3], "nested": { "a": "alpha", diff --git a/Tests/ParseSwiftTests/ParseAnonymousTests.swift b/Tests/ParseSwiftTests/ParseAnonymousTests.swift index 80409c895..bfca5748d 100644 --- a/Tests/ParseSwiftTests/ParseAnonymousTests.swift +++ b/Tests/ParseSwiftTests/ParseAnonymousTests.swift @@ -329,7 +329,7 @@ class ParseAnonymousTests: XCTestCase { var differentUser = User() differentUser.objectId = "nope" - differentUser.username = "shouldnot" + differentUser.username = "Shouldnot" differentUser.password = "work" do { _ = try await differentUser.signup() @@ -628,7 +628,7 @@ class ParseAnonymousTests: XCTestCase { let expectation1 = XCTestExpectation(description: "SignUp") var differentUser = User() differentUser.objectId = "nope" - differentUser.username = "shouldnot" + differentUser.username = "Shouldnot" differentUser.password = "work" differentUser.signup { result in if case let .failure(error) = result { diff --git a/Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift b/Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift index d563e0df5..7d51ed435 100644 --- a/Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift +++ b/Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift @@ -1130,7 +1130,7 @@ private struct Timestamp: Codable, Equatable { } static func ==(_ lhs: Timestamp, _ rhs: Timestamp) -> Bool { - return lhs.value == rhs.value + lhs.value == rhs.value } } @@ -1151,7 +1151,8 @@ fileprivate final class Counter: Codable, Equatable { } static func ==(_ lhs: Counter, _ rhs: Counter) -> Bool { - return lhs === rhs || lhs.count == rhs.count + lhs === rhs || + lhs.count == rhs.count } } @@ -1265,7 +1266,8 @@ private struct Company: Codable, Equatable { } static func ==(_ lhs: Company, _ rhs: Company) -> Bool { - return lhs.address == rhs.address && lhs.employees == rhs.employees + return lhs.address == rhs.address && + lhs.employees == rhs.employees } static var testValue: Company { @@ -1346,7 +1348,8 @@ fileprivate final class Mapping: Codable, Equatable { } static func ==(_ lhs: Mapping, _ rhs: Mapping) -> Bool { - return lhs === rhs || lhs.values == rhs.values + lhs === rhs || + lhs.values == rhs.values } static var testValue: Mapping { diff --git a/Tests/ParseSwiftTests/ParseLiveQueryTests.swift b/Tests/ParseSwiftTests/ParseLiveQueryTests.swift index 77062536d..41901390e 100644 --- a/Tests/ParseSwiftTests/ParseLiveQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseLiveQueryTests.swift @@ -1466,7 +1466,7 @@ class ParseLiveQueryTests: XCTestCase { } guard let url = URL(string: "wss://parse.com") else { - XCTFail("should create url") + XCTFail("Should create url") return } XCTAssertNotEqual(client.url, url) @@ -1486,7 +1486,7 @@ class ParseLiveQueryTests: XCTestCase { try await pretendToBeConnected(delegate) XCTAssertNil(delegate.error) guard let url = URL(string: "http://parse.com") else { - XCTFail("should create url") + XCTFail("Should create url") return } XCTAssertNotEqual(client.url, url) @@ -1512,7 +1512,7 @@ class ParseLiveQueryTests: XCTestCase { try await pretendToBeConnected(delegate) XCTAssertNil(delegate.error) guard let url = URL(string: "http://parse.com") else { - XCTFail("should create url") + XCTFail("Should create url") return } XCTAssertNotEqual(client.url, url) diff --git a/Tests/ParseSwiftTests/ParseObjectAsyncTests.swift b/Tests/ParseSwiftTests/ParseObjectAsyncTests.swift index c00c8c05d..d56a2647d 100644 --- a/Tests/ParseSwiftTests/ParseObjectAsyncTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectAsyncTests.swift @@ -178,37 +178,19 @@ class ParseObjectAsyncTests: XCTestCase { // swiftlint:disable:this type_body_le self.points = points } - /** - Conforms to Equatable by determining if an object has the same objectId. - - note: You can specify a custom way of `Equatable` if a more detailed way is needed. - - warning: If you use the default implementation, equatable will only work if the ParseObject - has been previously synced to the parse-server (has an objectId). In addition, if two - `ParseObject`'s have the same objectId, but were modified at different times, the - default implementation will still return true. In these cases you either want to use a - "struct" (value types) to make your `ParseObject`s instead of a class (reference type) or - provide your own implementation of `==`. - - parameter lhs: first object to compare - - parameter rhs: second object to compare - - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. - */ - public static func == (lhs: ParseObjectAsyncTests.GameScoreClass, - rhs: ParseObjectAsyncTests.GameScoreClass) -> Bool { - lhs.hasSameObjectId(as: rhs) - } - - /** - Conforms to `Hashable` using objectId. - - note: You can specify a custom way of `Hashable` if a more detailed way is needed. - - warning: If you use the default implementation, hash will only work if the ParseObject has been previously - synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId, - but were modified at different times, the default implementation will hash to the same value. In these - cases you either want to use a "struct" (value types) to make your `ParseObject`s instead of a - class (reference type) or provide your own implementation of `hash`. - - */ + public static func == ( + lhs: ParseObjectAsyncTests.GameScoreClass, + rhs: ParseObjectAsyncTests.GameScoreClass + ) -> Bool { + lhs.hasSameObjectId(as: rhs) && + lhs.createdAt == rhs.createdAt && + lhs.updatedAt == rhs.updatedAt + } + public func hash(into hasher: inout Hasher) { hasher.combine(self.id) + hasher.combine(createdAt) + hasher.combine(updatedAt) } } @@ -235,37 +217,19 @@ class ParseObjectAsyncTests: XCTestCase { // swiftlint:disable:this type_body_le self.gameScore = gameScore } - /** - Conforms to Equatable by determining if an object has the same objectId. - - note: You can specify a custom way of `Equatable` if a more detailed way is needed. - - warning: If you use the default implementation, equatable will only work if the ParseObject - has been previously synced to the parse-server (has an objectId). In addition, if two - `ParseObject`'s have the same objectId, but were modified at different times, the - default implementation will still return true. In these cases you either want to use a - "struct" (value types) to make your `ParseObject`s instead of a class (reference type) or - provide your own implementation of `==`. - - parameter lhs: first object to compare - - parameter rhs: second object to compare - - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. - */ - public static func == (lhs: ParseObjectAsyncTests.GameClass, - rhs: ParseObjectAsyncTests.GameClass) -> Bool { - lhs.hasSameObjectId(as: rhs) - } - - /** - Conforms to `Hashable` using objectId. - - note: You can specify a custom way of `Hashable` if a more detailed way is needed. - - warning: If you use the default implementation, hash will only work if the ParseObject has been previously - synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId, - but were modified at different times, the default implementation will hash to the same value. In these - cases you either want to use a "struct" (value types) to make your `ParseObject`s instead of a - class (reference type) or provide your own implementation of `hash`. - - */ + public static func == ( + lhs: ParseObjectAsyncTests.GameClass, + rhs: ParseObjectAsyncTests.GameClass + ) -> Bool { + lhs.hasSameObjectId(as: rhs) && + lhs.createdAt == rhs.createdAt && + lhs.updatedAt == rhs.updatedAt + } + public func hash(into hasher: inout Hasher) { hasher.combine(self.id) + hasher.combine(createdAt) + hasher.combine(updatedAt) } } diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index 5a7749678..ea002a26e 100644 --- a/Tests/ParseSwiftTests/ParseObjectTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectTests.swift @@ -157,37 +157,19 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length self.points = points } - /** - Conforms to Equatable by determining if an object has the same objectId. - - note: You can specify a custom way of `Equatable` if a more detailed way is needed. - - warning: If you use the default implementation, equatable will only work if the ParseObject - has been previously synced to the parse-server (has an objectId). In addition, if two - `ParseObject`'s have the same objectId, but were modified at different times, the - default implementation will still return true. In these cases you either want to use a - "struct" (value types) to make your `ParseObject`s instead of a class (reference type) or - provide your own implementation of `==`. - - parameter lhs: first object to compare - - parameter rhs: second object to compare - - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. - */ - public static func == (lhs: ParseObjectTests.GameScoreClass, - rhs: ParseObjectTests.GameScoreClass) -> Bool { + public static func == ( + lhs: ParseObjectTests.GameScoreClass, + rhs: ParseObjectTests.GameScoreClass + ) -> Bool { lhs.hasSameObjectId(as: rhs) + && lhs.createdAt == rhs.createdAt + && lhs.updatedAt == rhs.updatedAt } - /** - Conforms to `Hashable` using objectId. - - note: You can specify a custom way of `Hashable` if a more detailed way is needed. - - warning: If you use the default implementation, hash will only work if the ParseObject has been previously - synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId, - but were modified at different times, the default implementation will hash to the same value. In these - cases you either want to use a "struct" (value types) to make your `ParseObject`s instead of a - class (reference type) or provide your own implementation of `hash`. - - */ public func hash(into hasher: inout Hasher) { hasher.combine(self.id) + hasher.combine(createdAt) + hasher.combine(updatedAt) } } @@ -214,36 +196,16 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length self.gameScore = gameScore } - /** - Conforms to Equatable by determining if an object has the same objectId. - - note: You can specify a custom way of `Equatable` if a more detailed way is needed. - - warning: If you use the default implementation, equatable will only work if the ParseObject - has been previously synced to the parse-server (has an objectId). In addition, if two - `ParseObject`'s have the same objectId, but were modified at different times, the - default implementation will still return true. In these cases you either want to use a - "struct" (value types) to make your `ParseObject`s instead of a class (reference type) or - provide your own implementation of `==`. - - parameter lhs: first object to compare - - parameter rhs: second object to compare - - - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful. - */ public static func == (lhs: ParseObjectTests.GameClass, rhs: ParseObjectTests.GameClass) -> Bool { - lhs.hasSameObjectId(as: rhs) + lhs.hasSameObjectId(as: rhs) && + lhs.createdAt == rhs.createdAt && + lhs.updatedAt == rhs.updatedAt } - /** - Conforms to `Hashable` using objectId. - - note: You can specify a custom way of `Hashable` if a more detailed way is needed. - - warning: If you use the default implementation, hash will only work if the ParseObject has been previously - synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId, - but were modified at different times, the default implementation will hash to the same value. In these - cases you either want to use a "struct" (value types) to make your `ParseObject`s instead of a - class (reference type) or provide your own implementation of `hash`. - - */ public func hash(into hasher: inout Hasher) { hasher.combine(self.id) + hasher.combine(createdAt) + hasher.combine(updatedAt) } } diff --git a/Tests/ParseSwiftTests/ParseUserCombineTests.swift b/Tests/ParseSwiftTests/ParseUserCombineTests.swift index 3e88be460..63912e224 100644 --- a/Tests/ParseSwiftTests/ParseUserCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCombineTests.swift @@ -535,8 +535,8 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } if let installationFromMemory: CurrentInstallationContainer = try await ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromMemory.installationId == oldInstallationId - || installationFromMemory.installationId == nil { + if installationFromMemory.installationId == oldInstallationId || + installationFromMemory.installationId == nil { XCTFail("\(installationFromMemory) was not deleted and recreated in memory during logout") } } else { @@ -546,8 +546,8 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le #if !os(Linux) && !os(Android) && !os(Windows) if let installationFromKeychain: CurrentInstallationContainer = try await KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromKeychain.installationId == oldInstallationId - || installationFromKeychain.installationId == nil { + if installationFromKeychain.installationId == oldInstallationId || + installationFromKeychain.installationId == nil { XCTFail("\(installationFromKeychain) was not deleted & recreated in Keychain during logout") } } else { @@ -600,8 +600,8 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } if let installationFromMemory: CurrentInstallationContainer = try await ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromMemory.installationId == oldInstallationId - || installationFromMemory.installationId == nil { + if installationFromMemory.installationId == oldInstallationId || + installationFromMemory.installationId == nil { XCTFail("\(installationFromMemory) was not deleted & recreated in memory during logout") } } else { @@ -611,8 +611,8 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le #if !os(Linux) && !os(Android) && !os(Windows) if let installationFromKeychain: CurrentInstallationContainer = try await KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromKeychain.installationId == oldInstallationId - || installationFromKeychain.installationId == nil { + if installationFromKeychain.installationId == oldInstallationId || + installationFromKeychain.installationId == nil { XCTFail("\(installationFromKeychain) was not deleted & recreated in Keychain during logout") } } else { diff --git a/Tests/ParseSwiftTests/ParseUserTests.swift b/Tests/ParseSwiftTests/ParseUserTests.swift index 79e46bc40..3b2d51429 100644 --- a/Tests/ParseSwiftTests/ParseUserTests.swift +++ b/Tests/ParseSwiftTests/ParseUserTests.swift @@ -774,8 +774,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length if let installationFromMemory: CurrentInstallationContainer = try await ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromMemory.installationId == oldInstallationId - || installationFromMemory.installationId == nil { + if installationFromMemory.installationId == oldInstallationId || + installationFromMemory.installationId == nil { XCTFail("\(installationFromMemory) was not deleted and recreated in memory during logout") } } else { @@ -785,8 +785,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length #if !os(Linux) && !os(Android) && !os(Windows) if let installationFromKeychain: CurrentInstallationContainer = try await KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromKeychain.installationId == oldInstallationId - || installationFromKeychain.installationId == nil { + if installationFromKeychain.installationId == oldInstallationId || + installationFromKeychain.installationId == nil { XCTFail("\(installationFromKeychain) was not deleted & recreated in Keychain during logout") } } else { @@ -840,8 +840,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length if let installationFromMemory: CurrentInstallationContainer = try await ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromMemory.installationId == oldInstallationId - || installationFromMemory.installationId == nil { + if installationFromMemory.installationId == oldInstallationId || + installationFromMemory.installationId == nil { XCTFail("\(installationFromMemory) was not deleted & recreated in memory during logout") } } else { @@ -851,8 +851,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length #if !os(Linux) && !os(Android) && !os(Windows) if let installationFromKeychain: CurrentInstallationContainer = try await KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) { - if installationFromKeychain.installationId == oldInstallationId - || installationFromKeychain.installationId == nil { + if installationFromKeychain.installationId == oldInstallationId || + installationFromKeychain.installationId == nil { XCTFail("\(installationFromKeychain) was not deleted & recreated in Keychain during logout") } } else {