From a33f7c90cb389ba0d87be927d0b296b9f9b1bf8c Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sat, 13 Mar 2021 22:57:04 -0500 Subject: [PATCH 01/14] Allow generic return types for ParseCloud, hint, and explain --- .../Contents.swift | 4 + .../Contents.swift | 18 +- ParseSwift.playground/contents.xcplayground | 2 +- Sources/ParseSwift/API/API+Commands.swift | 2 +- Sources/ParseSwift/API/Responses.swift | 8 +- Sources/ParseSwift/Protocols/Queryable.swift | 2 +- .../ParseSwift/Types/ParseCloud+combine.swift | 4 +- Sources/ParseSwift/Types/ParseCloud.swift | 48 ++--- Sources/ParseSwift/Types/Query+combine.swift | 18 +- Sources/ParseSwift/Types/Query.swift | 110 ++++++----- .../ParseCloudCombineTests.swift | 14 +- Tests/ParseSwiftTests/ParseCloudTests.swift | 116 ++++-------- .../ParseQueryCombineTests.swift | 44 ++--- Tests/ParseSwiftTests/ParseQueryTests.swift | 172 ++++++------------ 14 files changed, 240 insertions(+), 322 deletions(-) diff --git a/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift index e4a6ee0a5..bd2aa8efc 100644 --- a/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift @@ -9,6 +9,10 @@ initializeParse() //: Create your own value typed `ParseCloud` type. struct Cloud: ParseCloud { + + //: Return type of your Cloud Function + typealias ReturnType = String + //: These are required for Object var functionJobName: String diff --git a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift index 97dd63c9f..081675d80 100644 --- a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift @@ -16,7 +16,7 @@ struct GameScore: ParseObject { var ACL: ParseACL? var location: ParseGeoPoint? //: Your own properties - var score: Int + var score: Int? //: A custom initializer. init(score: Int) { @@ -120,7 +120,6 @@ query3.find { results in switch results { case .success(let scores): - assert(scores.count >= 1) scores.forEach { (score) in print(""" Someone has a score of \"\(score.score)\" with no geopoint \(String(describing: score.location)) @@ -158,7 +157,6 @@ query7.find { results in switch results { case .success(let scores): - assert(scores.count >= 1) scores.forEach { (score) in print(""" Someone has a score of \"\(score.score)\" with geopoint using OR \(String(describing: score.location)) @@ -171,11 +169,19 @@ query7.find { results in } //: Explain the previous query. -let explain = try query2.find(explain: true) +let explain: AnyDecodable = try query2.first(explain: true) print(explain) -let hint = try query2.find(explain: false, hint: "objectId") -print(hint) +//: Hint of the previous query (asynchronous) +query2.find(explain: false, + hint: "_id_") { (result: Result<[GameScore], ParseError>) in + switch result { + case .success(let scores): + print(scores) + case .failure(let error): + print(error.localizedDescription) + } +} PlaygroundPage.current.finishExecution() //: [Next](@next) diff --git a/ParseSwift.playground/contents.xcplayground b/ParseSwift.playground/contents.xcplayground index b482d7b97..ab9557970 100644 --- a/ParseSwift.playground/contents.xcplayground +++ b/ParseSwift.playground/contents.xcplayground @@ -1,5 +1,5 @@ - + diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index 809c22c71..31cd39b9e 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -221,7 +221,7 @@ internal extension API { var urlRequest = URLRequest(url: urlComponents) urlRequest.allHTTPHeaderFields = headers if let urlBody = body { - if (urlBody as? ParseCloud) != nil { + if (urlBody as? CloudType) != nil { guard let bodyData = try? ParseCoding.parseEncoder().encode(urlBody, skipKeys: .cloud) else { return .failure(ParseError(code: .unknownError, message: "couldn't encode body \(urlBody)")) diff --git a/Sources/ParseSwift/API/Responses.swift b/Sources/ParseSwift/API/Responses.swift index 9c70e603c..0ea3e3d79 100644 --- a/Sources/ParseSwift/API/Responses.swift +++ b/Sources/ParseSwift/API/Responses.swift @@ -136,13 +136,13 @@ internal struct FileUploadResponse: Decodable { } // MARK: AnyResultResponse -internal struct AnyResultResponse: Codable { - let result: AnyCodable? +internal struct AnyResultResponse: Decodable { + let result: U } // MARK: AnyResultsResponse -internal struct AnyResultsResponse: Codable { - let results: AnyCodable? +internal struct AnyResultsResponse: Decodable { + let results: [U] } // MARK: ConfigResponse diff --git a/Sources/ParseSwift/Protocols/Queryable.swift b/Sources/ParseSwift/Protocols/Queryable.swift index e04cf9f9c..7d31b482e 100644 --- a/Sources/ParseSwift/Protocols/Queryable.swift +++ b/Sources/ParseSwift/Protocols/Queryable.swift @@ -11,7 +11,7 @@ public protocol Queryable { associatedtype ResultType func find(options: API.Options) throws -> [ResultType] - func first(options: API.Options) throws -> ResultType? + func first(options: API.Options) throws -> ResultType func count(options: API.Options) throws -> Int func find(options: API.Options, callbackQueue: DispatchQueue, completion: @escaping (Result<[ResultType], ParseError>) -> Void) diff --git a/Sources/ParseSwift/Types/ParseCloud+combine.swift b/Sources/ParseSwift/Types/ParseCloud+combine.swift index ef3405af5..07f4b4402 100644 --- a/Sources/ParseSwift/Types/ParseCloud+combine.swift +++ b/Sources/ParseSwift/Types/ParseCloud+combine.swift @@ -22,7 +22,7 @@ public extension ParseCloud { - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. */ - func runFunctionPublisher(options: API.Options = []) -> Future { + func runFunctionPublisher(options: API.Options = []) -> Future { Future { promise in self.runFunction(options: options, completion: promise) @@ -37,7 +37,7 @@ public extension ParseCloud { - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. */ - func startJobPublisher(options: API.Options = []) -> Future { + func startJobPublisher(options: API.Options = []) -> Future { Future { promise in self.startJob(options: options, completion: promise) diff --git a/Sources/ParseSwift/Types/ParseCloud.swift b/Sources/ParseSwift/Types/ParseCloud.swift index 65b436d01..c1bdb2b19 100644 --- a/Sources/ParseSwift/Types/ParseCloud.swift +++ b/Sources/ParseSwift/Types/ParseCloud.swift @@ -8,12 +8,16 @@ import Foundation +public protocol CloudType: Decodable, CustomDebugStringConvertible { } + /** Objects that conform to the `ParseCloud` protocol are able to call Parse Cloud Functions and Jobs. An object should be instantiated for each function and job type. When conforming to `ParseCloud`, any properties added will be passed as parameters to your Cloud Function or Job. */ -public protocol ParseCloud: ParseType, Decodable, CustomDebugStringConvertible { +public protocol ParseCloud: ParseType, CloudType { + + associatedtype ReturnType: Decodable /** The name of the function or job. */ @@ -27,10 +31,10 @@ extension ParseCloud { /** Calls a Cloud Code function *synchronously* and returns a result of it's execution. - parameter options: A set of header options sent to the server. Defaults to an empty set. - - returns: Returns a JSON response of `AnyCodable` type. + - returns: Returns a JSON response of `Decodable` type. - throws: An error of type `ParseError`. */ - public func runFunction(options: API.Options = []) throws -> AnyCodable { + public func runFunction(options: API.Options = []) throws -> ReturnType { try runFunctionCommand().execute(options: options, callbackQueue: .main) } @@ -39,11 +43,11 @@ extension ParseCloud { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: A block that will be called when logging out, completes or fails. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ public func runFunction(options: API.Options = [], callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { + completion: @escaping (Result) -> Void) { runFunctionCommand() .executeAsync(options: options, callbackQueue: callbackQueue) { result in callbackQueue.async { @@ -52,19 +56,20 @@ extension ParseCloud { } } - internal func runFunctionCommand() -> API.Command { + internal func runFunctionCommand() -> API.Command { return API.Command(method: .POST, path: .functions(name: functionJobName), - body: self) { (data) -> AnyCodable in - let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) - guard let result = response.result else { + body: self) { (data) -> ReturnType in + do { + let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) + return response.result + } catch { if let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data) { throw error } - return AnyCodable() + throw ParseError(code: .unknownError, message: "Couldn't decode data.") } - return result } } } @@ -74,9 +79,9 @@ extension ParseCloud { /** Starts a Cloud Code job *synchronously* and returns a result with the jobStatusId of the job. - parameter options: A set of header options sent to the server. Defaults to an empty set. - - returns: Returns a JSON response of `AnyCodable` type. + - returns: Returns a JSON response of `Decodable` type. */ - public func startJob(options: API.Options = []) throws -> AnyCodable { + public func startJob(options: API.Options = []) throws -> ReturnType { try startJobCommand().execute(options: options, callbackQueue: .main) } @@ -85,11 +90,11 @@ extension ParseCloud { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: A block that will be called when logging out, completes or fails. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ public func startJob(options: API.Options = [], callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { + completion: @escaping (Result) -> Void) { startJobCommand() .executeAsync(options: options, callbackQueue: callbackQueue) { result in callbackQueue.async { @@ -98,18 +103,19 @@ extension ParseCloud { } } - internal func startJobCommand() -> API.Command { + internal func startJobCommand() -> API.Command { return API.Command(method: .POST, path: .jobs(name: functionJobName), - body: self) { (data) -> AnyCodable in - let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) - guard let result = response.result else { + body: self) { (data) -> ReturnType in + do { + let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) + return response.result + } catch { if let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data) { throw error } - return AnyCodable() + throw ParseError(code: .unknownError, message: "Couldn't decode data.") } - return result } } } diff --git a/Sources/ParseSwift/Types/Query+combine.swift b/Sources/ParseSwift/Types/Query+combine.swift index d7b591231..5e4960bdd 100644 --- a/Sources/ParseSwift/Types/Query+combine.swift +++ b/Sources/ParseSwift/Types/Query+combine.swift @@ -35,9 +35,9 @@ public extension Query { - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. */ - func findPublisher(explain: Bool, - hint: String? = nil, - options: API.Options = []) -> Future { + func findPublisher(explain: Bool, + hint: String? = nil, + options: API.Options = []) -> Future<[U], ParseError> { Future { promise in self.find(explain: explain, hint: hint, @@ -65,9 +65,9 @@ public extension Query { - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. */ - func firstPublisher(explain: Bool, - hint: String? = nil, - options: API.Options = []) -> Future { + func firstPublisher(explain: Bool, + hint: String? = nil, + options: API.Options = []) -> Future { Future { promise in self.first(explain: explain, hint: hint, @@ -95,9 +95,9 @@ public extension Query { - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. */ - func countPublisher(explain: Bool, - hint: String? = nil, - options: API.Options = []) -> Future { + func countPublisher(explain: Bool, + hint: String? = nil, + options: API.Options = []) -> Future { Future { promise in self.count(explain: explain, hint: hint, diff --git a/Sources/ParseSwift/Types/Query.swift b/Sources/ParseSwift/Types/Query.swift index e0be2eb7a..af4d0294c 100644 --- a/Sources/ParseSwift/Types/Query.swift +++ b/Sources/ParseSwift/Types/Query.swift @@ -858,9 +858,11 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a dictionary of `AnyResultType` that is the JSON response of the query. + - returns: Returns a response of `Decodable` type to the query. */ - public func find(explain: Bool, hint: String? = nil, options: API.Options = []) throws -> AnyCodable { + public func find(explain: Bool, + hint: String? = nil, + options: API.Options = []) throws -> [U] { try findCommand(explain: explain, hint: hint).execute(options: options) } @@ -872,7 +874,8 @@ extension Query: Queryable { - parameter completion: The block to execute. It should have the following argument signature: `(Result<[ResultType], ParseError>)`. */ - public func find(options: API.Options = [], callbackQueue: DispatchQueue = .main, + public func find(options: API.Options = [], + callbackQueue: DispatchQueue = .main, completion: @escaping (Result<[ResultType], ParseError>) -> Void) { findCommand().executeAsync(options: options) { result in callbackQueue.async { @@ -889,11 +892,13 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: The block to execute. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ - public func find(explain: Bool, hint: String? = nil, options: API.Options = [], - callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { + public func find(explain: Bool, + hint: String? = nil, + options: API.Options = [], + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result<[U], ParseError>) -> Void) { findCommand(explain: explain, hint: hint).executeAsync(options: options) { result in callbackQueue.async { completion(result) @@ -908,9 +913,9 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a `ParseObject`, or `nil` if none was found. + - returns: Returns a `ParseObject`. */ - public func first(options: API.Options = []) throws -> ResultType? { + public func first(options: API.Options = []) throws -> ResultType { try firstCommand().execute(options: options) } @@ -923,9 +928,11 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a dictionary of `AnyResultType` that is the JSON response of the query. + - returns: Returns a response of `Decodable` type to the query. */ - public func first(explain: Bool, hint: String? = nil, options: API.Options = []) throws -> AnyCodable { + public func first(explain: Bool, + hint: String? = nil, + options: API.Options = []) throws -> U { try firstCommand(explain: explain, hint: hint).execute(options: options) } @@ -938,22 +945,12 @@ extension Query: Queryable { - parameter completion: The block to execute. It should have the following argument signature: `(Result)`. */ - public func first(options: API.Options = [], callbackQueue: DispatchQueue = .main, + public func first(options: API.Options = [], + callbackQueue: DispatchQueue = .main, completion: @escaping (Result) -> Void) { firstCommand().executeAsync(options: options) { result in - callbackQueue.async { - switch result { - case .success(let first): - guard let first = first else { - completion(.failure(ParseError(code: .objectNotFound, - message: "Object not found on the server."))) - return - } - completion(.success(first)) - case .failure(let error): - completion(.failure(error)) - } + completion(result) } } } @@ -967,11 +964,12 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of `.main`. - parameter completion: The block to execute. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ - public func first(explain: Bool, hint: String? = nil, options: API.Options = [], - callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { + public func first(explain: Bool, hint: String? = nil, + options: API.Options = [], + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void) { firstCommand(explain: explain, hint: hint).executeAsync(options: options) { result in callbackQueue.async { completion(result) @@ -999,9 +997,11 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a dictionary of `AnyResultType` that is the JSON response of the query. + - returns: Returns a response of `Decodable` type to the query. */ - public func count(explain: Bool, hint: String? = nil, options: API.Options = []) throws -> AnyCodable { + public func count(explain: Bool, + hint: String? = nil, + options: API.Options = []) throws -> U { try countCommand(explain: explain, hint: hint).execute(options: options) } @@ -1029,11 +1029,13 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of `.main`. - parameter completion: The block to execute. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ - public func count(explain: Bool, hint: String? = nil, options: API.Options = [], - callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { + public func count(explain: Bool, + hint: String? = nil, + options: API.Options = [], + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void) { countCommand(explain: explain, hint: hint).executeAsync(options: options) { result in callbackQueue.async { completion(result) @@ -1119,11 +1121,15 @@ extension Query { } } - func firstCommand() -> API.NonParseBodyCommand, ResultType?> { + func firstCommand() -> API.NonParseBodyCommand, ResultType> { var query = self query.limit = 1 return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) { - try ParseCoding.jsonDecoder().decode(QueryResponse.self, from: $0).results.first + if let decoded = try ParseCoding.jsonDecoder().decode(QueryResponse.self, from: $0).results.first { + return decoded + } + throw ParseError(code: .objectNotFound, + message: "Object not found on the server.") } } @@ -1131,47 +1137,51 @@ extension Query { var query = self query.limit = 1 query.isCount = true - return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) { + return API.NonParseBodyCommand(method: .POST, + path: query.endpoint, + body: query) { try ParseCoding.jsonDecoder().decode(QueryResponse.self, from: $0).count ?? 0 } } - func findCommand(explain: Bool, hint: String?) -> API.NonParseBodyCommand, AnyCodable> { + func findCommand(explain: Bool, + hint: String?) -> API.NonParseBodyCommand, [U]> { var query = self query.explain = explain query.hint = hint return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) { - if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results { - return results - } - return AnyCodable() + try ParseCoding.jsonDecoder().decode(AnyResultsResponse.self, from: $0).results } } - func firstCommand(explain: Bool, hint: String?) -> API.NonParseBodyCommand, AnyCodable> { + func firstCommand(explain: Bool, + hint: String?) -> API.NonParseBodyCommand, U> { var query = self query.limit = 1 query.explain = explain query.hint = hint return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) { - if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results { - return results + if let decoded: U = try ParseCoding.jsonDecoder().decode(AnyResultsResponse.self, from: $0).results.first { + return decoded } - return AnyCodable() + throw ParseError(code: .objectNotFound, + message: "Object not found on the server.") } } - func countCommand(explain: Bool, hint: String?) -> API.NonParseBodyCommand, AnyCodable> { + func countCommand(explain: Bool, + hint: String?) -> API.NonParseBodyCommand, U> { var query = self query.limit = 1 query.isCount = true query.explain = explain query.hint = hint return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) { - if let results = try JSONDecoder().decode(AnyResultsResponse.self, from: $0).results { - return results + if let decoded: U = try ParseCoding.jsonDecoder().decode(AnyResultsResponse.self, from: $0).results.first { + return decoded } - return AnyCodable() + throw ParseError(code: .objectNotFound, + message: "Object not found on the server.") } } diff --git a/Tests/ParseSwiftTests/ParseCloudCombineTests.swift b/Tests/ParseSwiftTests/ParseCloudCombineTests.swift index 367d79bf1..4ddfa5f7e 100644 --- a/Tests/ParseSwiftTests/ParseCloudCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseCloudCombineTests.swift @@ -17,10 +17,16 @@ import Combine class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_length struct Cloud: ParseCloud { + typealias ReturnType = String? // swiftlint:disable:this nesting + // Those are required for Object var functionJobName: String } + struct AnyResultResponse: Codable { + let result: U + } + override func setUpWithError() throws { super.setUp() guard let url = URL(string: "http://localhost:1337/1") else { @@ -47,7 +53,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - let response = AnyResultResponse(result: nil) + let response = AnyResultResponse(result: nil) MockURLProtocol.mockRequests { _ in do { @@ -69,7 +75,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l }, receiveValue: { functionResponse in - XCTAssertEqual(functionResponse, AnyCodable()) + XCTAssertNil(functionResponse) }) publisher.store(in: &subscriptions) @@ -80,7 +86,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - let response = AnyResultResponse(result: nil) + let response = AnyResultResponse(result: nil) MockURLProtocol.mockRequests { _ in do { @@ -102,7 +108,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l }, receiveValue: { functionResponse in - XCTAssertEqual(functionResponse, AnyCodable()) + XCTAssertNil(functionResponse) }) publisher.store(in: &subscriptions) diff --git a/Tests/ParseSwiftTests/ParseCloudTests.swift b/Tests/ParseSwiftTests/ParseCloudTests.swift index d0e7faa05..ed42c4562 100644 --- a/Tests/ParseSwiftTests/ParseCloudTests.swift +++ b/Tests/ParseSwiftTests/ParseCloudTests.swift @@ -13,11 +13,15 @@ import XCTest class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length struct Cloud: ParseCloud { + typealias ReturnType = String? // swiftlint:disable:this nesting + // Those are required for Object var functionJobName: String } struct Cloud2: ParseCloud { + typealias ReturnType = String? // swiftlint:disable:this nesting + // Those are required for Object var functionJobName: String @@ -25,6 +29,17 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length var customKey: String? } + struct Cloud3: ParseCloud { + typealias ReturnType = [String: String] // swiftlint:disable:this nesting + + // Those are required for Object + var functionJobName: String + } + + struct AnyResultResponse: Codable { + let result: U + } + override func setUpWithError() throws { try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { @@ -106,7 +121,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } func testFunction() { - let response = AnyResultResponse(result: nil) + let response = AnyResultResponse(result: nil) MockURLProtocol.mockRequests { _ in do { @@ -119,34 +134,30 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length do { let cloud = Cloud(functionJobName: "test") let functionResponse = try cloud.runFunction() - XCTAssertEqual(functionResponse, AnyCodable()) + XCTAssertNil(functionResponse) } catch { XCTFail(error.localizedDescription) } } func testFunction2() { - var result: AnyCodable = ["hello": "world"] + var result = ["hello": "world"] let response = AnyResultResponse(result: result) MockURLProtocol.mockRequests { _ in do { let encoded = try ParseCoding.jsonEncoder().encode(response) let encodedResult = try ParseCoding.jsonEncoder().encode(result) - result = try ParseCoding.jsonDecoder().decode(AnyCodable.self, from: encodedResult) + result = try ParseCoding.jsonDecoder().decode([String: String].self, from: encodedResult) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil } } do { - let cloud = Cloud(functionJobName: "test") + let cloud = Cloud3(functionJobName: "test") let functionResponse = try cloud.runFunction() - guard let resultAsDictionary = functionResponse.value as? [String: String] else { - XCTFail("Should have casted result to dictionary") - return - } - XCTAssertEqual(resultAsDictionary, ["hello": "world"]) + XCTAssertEqual(functionResponse, ["hello": "world"]) } catch { XCTFail(error.localizedDescription) } @@ -180,25 +191,16 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } } - func functionAsync(serverResponse: AnyCodable, callbackQueue: DispatchQueue) { + func functionAsync(serverResponse: [String: String], callbackQueue: DispatchQueue) { let expectation1 = XCTestExpectation(description: "Logout user1") - let cloud = Cloud(functionJobName: "test") + let cloud = Cloud3(functionJobName: "test") cloud.runFunction(callbackQueue: callbackQueue) { result in switch result { case .success(let response): - if serverResponse == AnyCodable() { - XCTAssertEqual(response, serverResponse) - } else { - guard let resultAsDictionary = serverResponse.value as? [String: String] else { - XCTFail("Should have casted result to dictionary") - expectation1.fulfill() - return - } - XCTAssertEqual(resultAsDictionary, ["hello": "world"]) - } + XCTAssertEqual(response, serverResponse) case .failure(let error): XCTFail(error.localizedDescription) } @@ -208,23 +210,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } func testFunctionMainQueue() { - let response = AnyResultResponse(result: nil) - - MockURLProtocol.mockRequests { _ in - do { - let encoded = try ParseCoding.jsonEncoder().encode(response) - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } catch { - return nil - } - } - - self.functionAsync(serverResponse: AnyCodable(), callbackQueue: .main) - } - - func testFunctionMainQueue2() { - let result: AnyCodable = ["hello": "world"] - let response = AnyResultResponse(result: result) + let response = AnyResultResponse(result: ["hello": "world"]) MockURLProtocol.mockRequests { _ in do { @@ -235,7 +221,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } } - self.functionAsync(serverResponse: result, callbackQueue: .main) + self.functionAsync(serverResponse: ["hello": "world"], callbackQueue: .main) } func functionAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) { @@ -295,7 +281,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } func testJob() { - let response = AnyResultResponse(result: nil) + let response = AnyResultResponse(result: nil) MockURLProtocol.mockRequests { _ in do { @@ -308,15 +294,14 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length do { let cloud = Cloud(functionJobName: "test") let functionResponse = try cloud.startJob() - XCTAssertEqual(functionResponse, AnyCodable()) + XCTAssertNil(functionResponse) } catch { XCTFail(error.localizedDescription) } } func testJob2() { - let result: AnyCodable = ["hello": "world"] - let response = AnyResultResponse(result: result) + let response = AnyResultResponse(result: ["hello": "world"]) MockURLProtocol.mockRequests { _ in do { @@ -327,13 +312,9 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } } do { - let cloud = Cloud(functionJobName: "test") + let cloud = Cloud3(functionJobName: "test") let functionResponse = try cloud.startJob() - guard let resultAsDictionary = functionResponse.value as? [String: String] else { - XCTFail("Should have casted result to dictionary") - return - } - XCTAssertEqual(resultAsDictionary, ["hello": "world"]) + XCTAssertEqual(functionResponse, response.result) } catch { XCTFail(error.localizedDescription) } @@ -367,25 +348,16 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } } - func jobAsync(serverResponse: AnyCodable, callbackQueue: DispatchQueue) { + func jobAsync(serverResponse: [String: String], callbackQueue: DispatchQueue) { let expectation1 = XCTestExpectation(description: "Logout user1") - let cloud = Cloud(functionJobName: "test") + let cloud = Cloud3(functionJobName: "test") cloud.startJob(callbackQueue: callbackQueue) { result in switch result { case .success(let response): - if serverResponse == AnyCodable() { - XCTAssertEqual(response, serverResponse) - } else { - guard let resultAsDictionary = serverResponse.value as? [String: String] else { - XCTFail("Should have casted result to dictionary") - expectation1.fulfill() - return - } - XCTAssertEqual(resultAsDictionary, ["hello": "world"]) - } + XCTAssertEqual(response, serverResponse) case .failure(let error): XCTFail(error.localizedDescription) } @@ -395,23 +367,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } func testJobMainQueue() { - let response = AnyResultResponse(result: nil) - - MockURLProtocol.mockRequests { _ in - do { - let encoded = try ParseCoding.jsonEncoder().encode(response) - return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) - } catch { - return nil - } - } - - self.jobAsync(serverResponse: AnyCodable(), callbackQueue: .main) - } - - func testJobMainQueue2() { - let result: AnyCodable = ["hello": "world"] - let response = AnyResultResponse(result: result) + let response = AnyResultResponse(result: ["hello": "world"]) MockURLProtocol.mockRequests { _ in do { @@ -422,7 +378,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } } - self.jobAsync(serverResponse: result, callbackQueue: .main) + self.jobAsync(serverResponse: ["hello": "world"], callbackQueue: .main) } func jobAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) { diff --git a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift index bed7a5df4..fcf4e179d 100644 --- a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift @@ -41,6 +41,14 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } } + struct AnyResultResponse: Codable { + let result: U + } + + struct AnyResultsResponse: Codable { + let results: U + } + override func setUpWithError() throws { super.setUp() guard let url = URL(string: "http://localhost:1337/1") else { @@ -111,7 +119,7 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -135,14 +143,8 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } expectation1.fulfill() - }, receiveValue: { queryResult in - - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + }, receiveValue: { (queryResult: [[String: String]]) in + XCTAssertEqual(queryResult, json.results) }) publisher.store(in: &subscriptions) @@ -193,7 +195,7 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -217,14 +219,8 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } expectation1.fulfill() - }, receiveValue: { queryResult in - - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + }, receiveValue: { (queryResult: [String: String]) in + XCTAssertEqual(queryResult, json.results.first) }) publisher.store(in: &subscriptions) @@ -275,7 +271,7 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var subscriptions = Set() let expectation1 = XCTestExpectation(description: "Save") - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -299,14 +295,8 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } expectation1.fulfill() - }, receiveValue: { queryResult in - - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + }, receiveValue: { (queryResult: [String: String]) in + XCTAssertEqual(queryResult, json.results.first) }) publisher.store(in: &subscriptions) diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index fc91a9b71..ce5233270 100644 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -36,7 +36,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length var ACL: ParseACL? } - override func setUp() { + struct AnyResultResponse: Codable { + let result: U + } + + struct AnyResultsResponse: Codable { + let results: [U] + } + + override func setUpWithError() throws { super.setUp() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") @@ -49,13 +57,13 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length testing: true) } - override func tearDown() { + override func tearDownWithError() throws { super.tearDown() MockURLProtocol.removeAll() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } // MARK: Initialization @@ -385,11 +393,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - - guard let score = try query.first(options: []) else { - XCTFail("Should unwrap first object found") - return - } + let score = try query.first(options: []) XCTAssert(score.hasSameObjectId(as: scoreOnServer)) } catch { XCTFail(error.localizedDescription) @@ -411,11 +415,8 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - - guard try query.first(options: []) == nil else { - XCTFail("Should have thrown error") - return - } + _ = try query.first(options: []) + XCTFail("Should have thrown error") } catch { guard let error = error as? ParseError else { XCTFail("Should have casted as ParseError") @@ -1912,7 +1913,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length // MARK: JSON Responses func testExplainFindSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -1928,20 +1929,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.find(explain: true) - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [[String: String]] = try query.find(explain: true) + XCTAssertEqual(queryResult, json.results) } catch { XCTFail("Error: \(error)") } } func testExplainFindAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -1957,17 +1953,11 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.find(explain: true, callbackQueue: .main) { result in + query.find(explain: true, callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results) case .failure(let error): XCTFail("Error: \(error)") } @@ -1977,7 +1967,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } func testExplainFirstSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -1993,20 +1983,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.first(explain: true) - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [String: String] = try query.first(explain: true) + XCTAssertEqual(queryResult, json.results.first) } catch { XCTFail("Error: \(error)") } } func testExplainFirstAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2022,17 +2007,11 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.first(explain: true, callbackQueue: .main) { result in + query.first(explain: true, callbackQueue: .main) { (result: Result<[String: String], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results.first) case .failure(let error): XCTFail("Error: \(error)") } @@ -2042,7 +2021,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } func testExplainCountSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2058,20 +2037,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.count(explain: true) - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [String: String] = try query.count(explain: true) + XCTAssertEqual(queryResult, json.results.first) } catch { XCTFail("Error: \(error)") } } func testExplainCountAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2087,17 +2061,11 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.count(explain: true, callbackQueue: .main) { result in + query.count(explain: true, callbackQueue: .main) { (result: Result<[String: String], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results.first) case .failure(let error): XCTFail("Error: \(error)") } @@ -2107,7 +2075,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } func testHintFindSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2123,20 +2091,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.find(explain: false, hint: "_id_") - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [[String: String]] = try query.find(explain: false, hint: "_id_") + XCTAssertEqual(queryResult, json.results) } catch { XCTFail("Error: \(error)") } } func testHintFindAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2152,17 +2115,13 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.find(explain: false, hint: "_id_", callbackQueue: .main) { result in + query.find(explain: false, + hint: "_id_", + callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results) case .failure(let error): XCTFail("Error: \(error)") } @@ -2172,7 +2131,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } func testHintFirstSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2188,20 +2147,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.first(explain: false, hint: "_id_") - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [String: String] = try query.first(explain: false, hint: "_id_") + XCTAssertEqual(queryResult, json.results.first) } catch { XCTFail("Error: \(error)") } } func testHintFirstAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2217,17 +2171,13 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.first(explain: false, hint: "_id_", callbackQueue: .main) { result in + query.first(explain: false, + hint: "_id_", + callbackQueue: .main) { (result: Result<[String: String], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results.first) case .failure(let error): XCTFail("Error: \(error)") } @@ -2237,7 +2187,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } func testHintCountSynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2253,20 +2203,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let query = GameScore.query() do { - let queryResult = try query.count(explain: false, hint: "_id_") - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - return - } - XCTAssertEqual(response, expected) + let queryResult: [String: String] = try query.count(explain: false, hint: "_id_") + XCTAssertEqual(queryResult, json.results.first) } catch { XCTFail("Error: \(error)") } } func testHintCountAsynchronous() { - let json = AnyResultsResponse(results: ["yolo": "yarr"]) + let json = AnyResultsResponse(results: [["yolo": "yarr"]]) let encoded: Data! do { @@ -2282,17 +2227,12 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let expectation = XCTestExpectation(description: "Fetch object") let query = GameScore.query() - query.count(explain: false, hint: "_id_", callbackQueue: .main) { result in + query.count(explain: false, hint: "_id_", + callbackQueue: .main) { (result: Result<[String: String], ParseError>) in switch result { case .success(let queryResult): - guard let response = queryResult.value as? [String: String], - let expected = json.results?.value as? [String: String] else { - XCTFail("Error: Should cast to string") - expectation.fulfill() - return - } - XCTAssertEqual(response, expected) + XCTAssertEqual(queryResult, json.results.first) case .failure(let error): XCTFail("Error: \(error)") } From ea51368aa92b2472ae3c2e3b2b57036fffa934cf Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sat, 13 Mar 2021 23:10:00 -0500 Subject: [PATCH 02/14] Change encoder/decoder of in memory storage --- Sources/ParseSwift/Storage/ParseKeyValueStore.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ParseSwift/Storage/ParseKeyValueStore.swift b/Sources/ParseSwift/Storage/ParseKeyValueStore.swift index 13eb25a75..aa64ee6d3 100644 --- a/Sources/ParseSwift/Storage/ParseKeyValueStore.swift +++ b/Sources/ParseSwift/Storage/ParseKeyValueStore.swift @@ -32,8 +32,8 @@ public protocol ParseKeyValueStore { /// It works by encoding / decoding all values just like a real `Codable` store would /// but it stores all values as `Data` blobs in memory. struct InMemoryKeyValueStore: ParseKeyValueStore { - var decoder = JSONDecoder() - var encoder = JSONEncoder() + var decoder = ParseCoding.jsonDecoder() + var encoder = ParseCoding.jsonEncoder() var storage = [String: Data]() mutating func delete(valueFor key: String) throws { From 60d0356559a985cc948942d8f756c1a805481d40 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sat, 13 Mar 2021 23:35:55 -0500 Subject: [PATCH 03/14] Make all test cases throw on setup and teardown --- Tests/ParseSwiftTests/APICommandTests.swift | 12 ++++++------ Tests/ParseSwiftTests/KeychainStoreTests.swift | 8 ++++---- Tests/ParseSwiftTests/ParseACLTests.swift | 12 ++++++------ .../ParseSwiftTests/ParseAnonymousCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseAppleCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseCloudCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseCloudTests.swift | 2 +- Tests/ParseSwiftTests/ParseConfigCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseConfigTests.swift | 2 +- Tests/ParseSwiftTests/ParseFileCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseGeoPointTests.swift | 12 ++++++------ .../ParseInstallationCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseInstallationTests.swift | 12 ++++++------ Tests/ParseSwiftTests/ParseLDAPCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseObjectBatchTests.swift | 12 ++++++------ Tests/ParseSwiftTests/ParseObjectCombine.swift | 4 ++-- Tests/ParseSwiftTests/ParseObjectTests.swift | 6 +++--- .../ParseSwiftTests/ParseOperationCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseQueryCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseQueryTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseUserCombineTests.swift | 4 ++-- Tests/ParseSwiftTests/ParseUserTests.swift | 6 +++--- 22 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Tests/ParseSwiftTests/APICommandTests.swift b/Tests/ParseSwiftTests/APICommandTests.swift index 94c705e18..c1b1b3fef 100644 --- a/Tests/ParseSwiftTests/APICommandTests.swift +++ b/Tests/ParseSwiftTests/APICommandTests.swift @@ -12,8 +12,8 @@ import XCTest class APICommandTests: XCTestCase { - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -25,13 +25,13 @@ class APICommandTests: XCTestCase { testing: true) } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } func testExecuteCorrectly() { diff --git a/Tests/ParseSwiftTests/KeychainStoreTests.swift b/Tests/ParseSwiftTests/KeychainStoreTests.swift index 4ffc7e7a1..03c7bd62a 100644 --- a/Tests/ParseSwiftTests/KeychainStoreTests.swift +++ b/Tests/ParseSwiftTests/KeychainStoreTests.swift @@ -12,13 +12,13 @@ import XCTest class KeychainStoreTests: XCTestCase { var testStore: KeychainStore! - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() testStore = KeychainStore(service: "test") } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() _ = testStore.removeAllObjects() } diff --git a/Tests/ParseSwiftTests/ParseACLTests.swift b/Tests/ParseSwiftTests/ParseACLTests.swift index f9a7f82b1..b08fd7579 100644 --- a/Tests/ParseSwiftTests/ParseACLTests.swift +++ b/Tests/ParseSwiftTests/ParseACLTests.swift @@ -12,8 +12,8 @@ import XCTest class ParseACLTests: XCTestCase { - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -24,12 +24,12 @@ class ParseACLTests: XCTestCase { serverURL: url, testing: true) } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } struct User: ParseUser { diff --git a/Tests/ParseSwiftTests/ParseAnonymousCombineTests.swift b/Tests/ParseSwiftTests/ParseAnonymousCombineTests.swift index f1dff0e3e..ff9b429e6 100644 --- a/Tests/ParseSwiftTests/ParseAnonymousCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseAnonymousCombineTests.swift @@ -61,7 +61,7 @@ class ParseAuthenticationCombineTests: XCTestCase { // swiftlint:disable:this ty } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -74,7 +74,7 @@ class ParseAuthenticationCombineTests: XCTestCase { // swiftlint:disable:this ty } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseAppleCombineTests.swift b/Tests/ParseSwiftTests/ParseAppleCombineTests.swift index ed6e02a2f..d7a52afed 100644 --- a/Tests/ParseSwiftTests/ParseAppleCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseAppleCombineTests.swift @@ -62,7 +62,7 @@ class ParseAppleCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -75,7 +75,7 @@ class ParseAppleCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseCloudCombineTests.swift b/Tests/ParseSwiftTests/ParseCloudCombineTests.swift index 4ddfa5f7e..c45097c61 100644 --- a/Tests/ParseSwiftTests/ParseCloudCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseCloudCombineTests.swift @@ -28,7 +28,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -41,7 +41,7 @@ class ParseCloudCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseCloudTests.swift b/Tests/ParseSwiftTests/ParseCloudTests.swift index ed42c4562..f0c8e3cd8 100644 --- a/Tests/ParseSwiftTests/ParseCloudTests.swift +++ b/Tests/ParseSwiftTests/ParseCloudTests.swift @@ -54,7 +54,7 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseConfigCombineTests.swift b/Tests/ParseSwiftTests/ParseConfigCombineTests.swift index 5d471cb30..27ec0754b 100644 --- a/Tests/ParseSwiftTests/ParseConfigCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseConfigCombineTests.swift @@ -70,7 +70,7 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -83,7 +83,7 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseConfigTests.swift b/Tests/ParseSwiftTests/ParseConfigTests.swift index 0ac54ee80..861a496cc 100644 --- a/Tests/ParseSwiftTests/ParseConfigTests.swift +++ b/Tests/ParseSwiftTests/ParseConfigTests.swift @@ -79,7 +79,7 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseFileCombineTests.swift b/Tests/ParseSwiftTests/ParseFileCombineTests.swift index 4a8162d02..983982d9d 100644 --- a/Tests/ParseSwiftTests/ParseFileCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseFileCombineTests.swift @@ -24,7 +24,7 @@ class ParseFileCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -41,7 +41,7 @@ class ParseFileCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseGeoPointTests.swift b/Tests/ParseSwiftTests/ParseGeoPointTests.swift index ddbf27397..23e5fabd8 100644 --- a/Tests/ParseSwiftTests/ParseGeoPointTests.swift +++ b/Tests/ParseSwiftTests/ParseGeoPointTests.swift @@ -13,8 +13,8 @@ import CoreLocation @testable import ParseSwift class ParseGeoPointTests: XCTestCase { - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -26,13 +26,13 @@ class ParseGeoPointTests: XCTestCase { testing: true) } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } func testDefaults() { diff --git a/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift b/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift index 3f0d87b0b..80dce92ee 100644 --- a/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseInstallationCombineTests.swift @@ -89,7 +89,7 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type let loginPassword = "world" override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -103,7 +103,7 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseInstallationTests.swift b/Tests/ParseSwiftTests/ParseInstallationTests.swift index 7826ab017..141595655 100644 --- a/Tests/ParseSwiftTests/ParseInstallationTests.swift +++ b/Tests/ParseSwiftTests/ParseInstallationTests.swift @@ -86,8 +86,8 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l let testInstallationObjectId = "yarr" - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -100,13 +100,13 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l userLogin() } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } func userLogin() { diff --git a/Tests/ParseSwiftTests/ParseLDAPCombineTests.swift b/Tests/ParseSwiftTests/ParseLDAPCombineTests.swift index a1403428f..bc3e81ed8 100644 --- a/Tests/ParseSwiftTests/ParseLDAPCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseLDAPCombineTests.swift @@ -62,7 +62,7 @@ class ParseLDAPCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -75,7 +75,7 @@ class ParseLDAPCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index cc17c1a7c..8471b7241 100644 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -32,8 +32,8 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le } } - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -45,13 +45,13 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le testing: true) } - override func tearDown() { - super.tearDown() + override func tearDownWithError() throws { + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) - try? KeychainStore.shared.deleteAll() + try KeychainStore.shared.deleteAll() #endif - try? ParseStorage.shared.deleteAll() + try ParseStorage.shared.deleteAll() } //COREY: Linux decodes this differently for some reason diff --git a/Tests/ParseSwiftTests/ParseObjectCombine.swift b/Tests/ParseSwiftTests/ParseObjectCombine.swift index 2d70b0666..47480c9b7 100644 --- a/Tests/ParseSwiftTests/ParseObjectCombine.swift +++ b/Tests/ParseSwiftTests/ParseObjectCombine.swift @@ -42,7 +42,7 @@ class ParseObjectCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -55,7 +55,7 @@ class ParseObjectCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index 7db966848..8afca1e53 100644 --- a/Tests/ParseSwiftTests/ParseObjectTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectTests.swift @@ -186,8 +186,8 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length } } - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -200,7 +200,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseOperationCombineTests.swift b/Tests/ParseSwiftTests/ParseOperationCombineTests.swift index 8067b6437..15ca4bd29 100644 --- a/Tests/ParseSwiftTests/ParseOperationCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseOperationCombineTests.swift @@ -42,7 +42,7 @@ class ParseOperationCombineTests: XCTestCase { // swiftlint:disable:this type_bo } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -55,7 +55,7 @@ class ParseOperationCombineTests: XCTestCase { // swiftlint:disable:this type_bo } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift index fcf4e179d..7f822ff68 100644 --- a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift @@ -50,7 +50,7 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -63,7 +63,7 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index ce5233270..36c1988a0 100644 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -45,7 +45,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -58,7 +58,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseUserCombineTests.swift b/Tests/ParseSwiftTests/ParseUserCombineTests.swift index 480316ddc..b01dd0109 100644 --- a/Tests/ParseSwiftTests/ParseUserCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCombineTests.swift @@ -68,7 +68,7 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le let loginPassword = "world" override func setUpWithError() throws { - super.setUp() + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -81,7 +81,7 @@ class ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_le } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() diff --git a/Tests/ParseSwiftTests/ParseUserTests.swift b/Tests/ParseSwiftTests/ParseUserTests.swift index aee6f831e..40886d649 100644 --- a/Tests/ParseSwiftTests/ParseUserTests.swift +++ b/Tests/ParseSwiftTests/ParseUserTests.swift @@ -63,8 +63,8 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length let loginUserName = "hello10" let loginPassword = "world" - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() guard let url = URL(string: "http://localhost:1337/1") else { XCTFail("Should create valid URL") return @@ -77,7 +77,7 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length } override func tearDownWithError() throws { - super.tearDown() + try super.tearDownWithError() MockURLProtocol.removeAll() #if !os(Linux) try KeychainStore.shared.deleteAll() From e3a12ed0464fe7a196bb8dfeab7d08fb2efceaf0 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 10:03:51 -0400 Subject: [PATCH 04/14] nits, improve decoding error reporting --- Sources/ParseSwift/Objects/ParseObject.swift | 13 +++++++------ Sources/ParseSwift/Types/ParseCloud.swift | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index aad1e618c..81d817af1 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -494,13 +494,14 @@ extension ParseObject { completion(result) } } - } catch let error as ParseError { - callbackQueue.async { - completion(.failure(error)) - } } catch { callbackQueue.async { - completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription))) + if let error = error as? ParseError { + completion(.failure(error)) + } else { + completion(.failure(ParseError(code: .unknownError, + message: error.localizedDescription))) + } } } } @@ -601,7 +602,7 @@ extension ParseObject { } internal func saveCommand() -> API.Command { - return API.Command.saveCommand(self) + API.Command.saveCommand(self) } // swiftlint:disable:next function_body_length diff --git a/Sources/ParseSwift/Types/ParseCloud.swift b/Sources/ParseSwift/Types/ParseCloud.swift index c1bdb2b19..6f3286534 100644 --- a/Sources/ParseSwift/Types/ParseCloud.swift +++ b/Sources/ParseSwift/Types/ParseCloud.swift @@ -31,7 +31,7 @@ extension ParseCloud { /** Calls a Cloud Code function *synchronously* and returns a result of it's execution. - parameter options: A set of header options sent to the server. Defaults to an empty set. - - returns: Returns a JSON response of `Decodable` type. + - returns: Returns a `Decodable` type. - throws: An error of type `ParseError`. */ public func runFunction(options: API.Options = []) throws -> ReturnType { @@ -79,7 +79,7 @@ extension ParseCloud { /** Starts a Cloud Code job *synchronously* and returns a result with the jobStatusId of the job. - parameter options: A set of header options sent to the server. Defaults to an empty set. - - returns: Returns a JSON response of `Decodable` type. + - returns: Returns a `Decodable` type. */ public func startJob(options: API.Options = []) throws -> ReturnType { try startJobCommand().execute(options: options, callbackQueue: .main) From 95e549b2e31a749f5d424abf74ba17fe5dfb3bfe Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 10:05:30 -0400 Subject: [PATCH 05/14] nits and improved error reporting --- Sources/ParseSwift/API/URLSession+extensions.swift | 2 +- Sources/ParseSwift/Objects/ParseInstallation.swift | 11 ++++++----- Sources/ParseSwift/Objects/ParseUser.swift | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Sources/ParseSwift/API/URLSession+extensions.swift b/Sources/ParseSwift/API/URLSession+extensions.swift index 97ad5b557..c1f92af51 100755 --- a/Sources/ParseSwift/API/URLSession+extensions.swift +++ b/Sources/ParseSwift/API/URLSession+extensions.swift @@ -45,7 +45,7 @@ extension URLSession { guard let parseError = error as? ParseError else { return .failure(ParseError(code: .unknownError, // swiftlint:disable:next line_length - message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription)")) + message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription). Format: \(String(describing: String(data: responseData, encoding: .utf8)))")) } return .failure(parseError) } diff --git a/Sources/ParseSwift/Objects/ParseInstallation.swift b/Sources/ParseSwift/Objects/ParseInstallation.swift index 61a646838..3935a707f 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation.swift @@ -395,13 +395,14 @@ extension ParseInstallation { completion(result) } } - } catch let error as ParseError { - callbackQueue.async { - completion(.failure(error)) - } } catch { callbackQueue.async { - completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription))) + if let error = error as? ParseError { + completion(.failure(error)) + } else { + completion(.failure(ParseError(code: .unknownError, + message: error.localizedDescription))) + } } } } diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 03cbbf414..0dbac1ccd 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -706,13 +706,14 @@ extension ParseUser { } } } - } catch let error as ParseError { - callbackQueue.async { - completion(.failure(error)) - } } catch { callbackQueue.async { - completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription))) + if let error = error as? ParseError { + completion(.failure(error)) + } else { + completion(.failure(ParseError(code: .unknownError, + message: error.localizedDescription))) + } } } } From d9c8e2ca5f2ded1d1363d40b217d2f4525aa12af Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 10:17:41 -0400 Subject: [PATCH 06/14] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39fc970f5..3cbf6dc07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,15 @@ ### 1.1.7 [Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...1.1.7) +__Breaking changes__ +- Allows return types to be specified for `ParseCloud`, query `hint`, and `explain` (see playgrounds for examples). Changed functionality of synchronous `query.first()`. It use to return nil if no values are found. Now it will throw an error if none are found. ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6). + __New features__ - Add transaction support to batch saveAll and deleteAll ([#89](https://github.com/parse-community/Parse-Swift/pull/89)), thanks to [Corey Baker](https://github.com/cbaker6). - Add modifiers to containsString, hasPrefix, hasSuffix ([#85](https://github.com/parse-community/Parse-Swift/pull/85)), thanks to [Corey Baker](https://github.com/cbaker6). __Improvements__ +- Better error reporting when decode errors occur ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6). - Can use a variadic version of exclude. Added examples of select and exclude query in playgrounds ([#88](https://github.com/parse-community/Parse-Swift/pull/88)), thanks to [Corey Baker](https://github.com/cbaker6). ### 1.1.6 From c241c382df60e24aeb8c7a33b51b96cb8c17f6e4 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 10:48:12 -0400 Subject: [PATCH 07/14] Improve decode error --- Sources/ParseSwift/API/URLSession+extensions.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/ParseSwift/API/URLSession+extensions.swift b/Sources/ParseSwift/API/URLSession+extensions.swift index c1f92af51..b7300552a 100755 --- a/Sources/ParseSwift/API/URLSession+extensions.swift +++ b/Sources/ParseSwift/API/URLSession+extensions.swift @@ -43,9 +43,16 @@ extension URLSession { return .failure(error) } guard let parseError = error as? ParseError else { + if let json = try? JSONSerialization + .data(withJSONObject: responseData, + options: .prettyPrinted) { + return .failure(ParseError(code: .unknownError, + // swiftlint:disable:next line_length + message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: json, encoding: .utf8)))")) + } return .failure(ParseError(code: .unknownError, // swiftlint:disable:next line_length - message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription). Format: \(String(describing: String(data: responseData, encoding: .utf8)))")) + message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: responseData, encoding: .utf8)))")) } return .failure(parseError) } From c4d6370849a280a24ccffc8bf06abdbb9d2b6914 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 11:36:35 -0400 Subject: [PATCH 08/14] Improve decode error reporting and add test case --- .../API/URLSession+extensions.swift | 11 +++++---- Tests/ParseSwiftTests/ParseQueryTests.swift | 24 ++++++++++++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Sources/ParseSwift/API/URLSession+extensions.swift b/Sources/ParseSwift/API/URLSession+extensions.swift index b7300552a..828fd5a62 100755 --- a/Sources/ParseSwift/API/URLSession+extensions.swift +++ b/Sources/ParseSwift/API/URLSession+extensions.swift @@ -43,16 +43,17 @@ extension URLSession { return .failure(error) } guard let parseError = error as? ParseError else { - if let json = try? JSONSerialization - .data(withJSONObject: responseData, - options: .prettyPrinted) { + guard JSONSerialization.isValidJSONObject(responseData) == true, + let json = try? JSONSerialization + .data(withJSONObject: responseData, + options: .prettyPrinted) else { return .failure(ParseError(code: .unknownError, // swiftlint:disable:next line_length - message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: json, encoding: .utf8)))")) + message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: responseData, encoding: .utf8)))")) } return .failure(ParseError(code: .unknownError, // swiftlint:disable:next line_length - message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: responseData, encoding: .utf8)))")) + message: "Error decoding parse-server response: \(String(describing: urlResponse)) with error: \(error.localizedDescription) Format: \(String(describing: String(data: json, encoding: .utf8)))")) } return .failure(parseError) } diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index 36c1988a0..fd212ecaa 100644 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -28,12 +28,14 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } } - struct GameType: ParseObject { + struct GameScoreBroken: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? var updatedAt: Date? var ACL: ParseACL? + + var score: Int? //Left as non-optional to throw error on pointer } struct AnyResultResponse: Codable { @@ -398,7 +400,27 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length } catch { XCTFail(error.localizedDescription) } + } + func testFirstThrowDecodingError() { + var scoreOnServer = GameScoreBroken() + scoreOnServer.objectId = "yarr" + scoreOnServer.createdAt = Date() + scoreOnServer.updatedAt = scoreOnServer.createdAt + scoreOnServer.ACL = nil + + let results = QueryResponse(results: [scoreOnServer], count: 1) + MockURLProtocol.mockRequests { _ in + do { + let encoded = try ParseCoding.jsonEncoder().encode(results) + return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) + } catch { + return nil + } + } + + let query = GameScore.query() + XCTAssertThrowsError(try query.first(options: [])) } func testFirstNoObjectFound() { From 2fd2aa454542d9a889de1e63913863cae7e3b5bc Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 12:31:51 -0400 Subject: [PATCH 09/14] tweak keychain tests --- Tests/ParseSwiftTests/ParseConfigCombineTests.swift | 6 ++---- Tests/ParseSwiftTests/ParseConfigTests.swift | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Tests/ParseSwiftTests/ParseConfigCombineTests.swift b/Tests/ParseSwiftTests/ParseConfigCombineTests.swift index 27ec0754b..745e7f878 100644 --- a/Tests/ParseSwiftTests/ParseConfigCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseConfigCombineTests.swift @@ -145,6 +145,7 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ }, receiveValue: { fetched in XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage) + XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -155,8 +156,6 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage) #endif - - XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) }) publisher.store(in: &subscriptions) @@ -195,6 +194,7 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ }, receiveValue: { saved in XCTAssertTrue(saved) + XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -205,8 +205,6 @@ class ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_ } XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage) #endif - - XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) }) publisher.store(in: &subscriptions) diff --git a/Tests/ParseSwiftTests/ParseConfigTests.swift b/Tests/ParseSwiftTests/ParseConfigTests.swift index 861a496cc..372fd6c92 100644 --- a/Tests/ParseSwiftTests/ParseConfigTests.swift +++ b/Tests/ParseSwiftTests/ParseConfigTests.swift @@ -163,6 +163,7 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length do { let fetched = try config.fetch() XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage) + XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -174,7 +175,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage) #endif - XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) } catch { XCTFail(error.localizedDescription) } @@ -205,6 +205,7 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length case .success(let fetched): XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage) + XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -217,7 +218,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage) #endif - XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage) case .failure(let error): XCTFail(error.localizedDescription) } @@ -256,6 +256,7 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length do { let saved = try config.save() XCTAssertTrue(saved) + XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -266,8 +267,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length } XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage) #endif - - XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) } catch { XCTFail(error.localizedDescription) } @@ -297,6 +296,7 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length case .success(let saved): XCTAssertTrue(saved) + XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) #if !os(Linux) //Should be updated in Keychain @@ -309,7 +309,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage) #endif - XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage) case .failure(let error): XCTFail(error.localizedDescription) } From 524403b251f49e31009e43b83673b0eb84b9d213 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 12:58:15 -0400 Subject: [PATCH 10/14] Remove unnecessary error check --- Sources/ParseSwift/Types/ParseCloud.swift | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/Sources/ParseSwift/Types/ParseCloud.swift b/Sources/ParseSwift/Types/ParseCloud.swift index 6f3286534..8382b88bf 100644 --- a/Sources/ParseSwift/Types/ParseCloud.swift +++ b/Sources/ParseSwift/Types/ParseCloud.swift @@ -61,15 +61,8 @@ extension ParseCloud { return API.Command(method: .POST, path: .functions(name: functionJobName), body: self) { (data) -> ReturnType in - do { - let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) - return response.result - } catch { - if let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data) { - throw error - } - throw ParseError(code: .unknownError, message: "Couldn't decode data.") - } + let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) + return response.result } } } @@ -107,15 +100,8 @@ extension ParseCloud { return API.Command(method: .POST, path: .jobs(name: functionJobName), body: self) { (data) -> ReturnType in - do { - let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) - return response.result - } catch { - if let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data) { - throw error - } - throw ParseError(code: .unknownError, message: "Couldn't decode data.") - } + let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse.self, from: data) + return response.result } } } From 742f8a17ec312f24d00102da48d873bf4d638112 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 13:15:50 -0400 Subject: [PATCH 11/14] lower codecov patch --- .codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index 5148b8498..2517c8e20 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -5,7 +5,7 @@ coverage: status: patch: default: - target: auto + target: 72 changes: false project: default: From cb0f50f0463deb2c5094bbf324689f71cb0a9255 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 13:29:42 -0400 Subject: [PATCH 12/14] Prepare 1.2.0 release --- CHANGELOG.md | 6 +++--- ParseSwift.podspec | 2 +- Scripts/jazzy.sh | 2 +- Sources/ParseSwift/ParseConstants.swift | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cbf6dc07..1f17b7d8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Parse-Swift Changelog ### main -[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.7...main) +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.0...main) * _Contributing to this repo? Add info about your change here to be included in the next release_ -### 1.1.7 -[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...1.1.7) +### 1.2.0 +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...1.2.0) __Breaking changes__ - Allows return types to be specified for `ParseCloud`, query `hint`, and `explain` (see playgrounds for examples). Changed functionality of synchronous `query.first()`. It use to return nil if no values are found. Now it will throw an error if none are found. ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6). diff --git a/ParseSwift.podspec b/ParseSwift.podspec index 8e4c51a08..09a584f74 100644 --- a/ParseSwift.podspec +++ b/ParseSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "ParseSwift" - s.version = "1.1.7" + s.version = "1.2.0" s.summary = "Parse Pure Swift SDK" s.homepage = "https://github.com/parse-community/Parse-Swift" s.authors = { diff --git a/Scripts/jazzy.sh b/Scripts/jazzy.sh index 3a0a8df81..46d9a287c 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.1.7 \ + --module-version 1.2.0 \ --theme fullwidth \ --skip-undocumented \ --output ./docs/api \ diff --git a/Sources/ParseSwift/ParseConstants.swift b/Sources/ParseSwift/ParseConstants.swift index 0e9248139..bd9d67ca0 100644 --- a/Sources/ParseSwift/ParseConstants.swift +++ b/Sources/ParseSwift/ParseConstants.swift @@ -9,7 +9,7 @@ import Foundation enum ParseConstants { - static let parseVersion = "1.1.7" + static let parseVersion = "1.2.0" static let hashingKey = "parseSwift" static let fileManagementDirectory = "parse/" static let fileManagementPrivateDocumentsDirectory = "Private Documents/" From a80705accaf0513799afd4eafef89c288c08c485 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 19:34:36 -0400 Subject: [PATCH 13/14] Add date decoding test --- Sources/ParseSwift/Coding/ParseCoding.swift | 2 +- Tests/ParseSwiftTests/ParseEncoderTests.swift | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index ee0808e0e..2005e6f45 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -76,7 +76,7 @@ extension ParseCoding { message: "An invalid date string was provided when decoding dates." ) } - } catch let error { + } catch { let container = try decoder.container(keyedBy: DateEncodingKeys.self) if diff --git a/Tests/ParseSwiftTests/ParseEncoderTests.swift b/Tests/ParseSwiftTests/ParseEncoderTests.swift index 5cce56ea8..07eee4b7b 100644 --- a/Tests/ParseSwiftTests/ParseEncoderTests.swift +++ b/Tests/ParseSwiftTests/ParseEncoderTests.swift @@ -92,4 +92,13 @@ class ParseEncoderTests: XCTestCase { XCTAssertNil(decoded["updatedAt"]) XCTAssertNil(decoded["className"]) } + + func testDateStringEncoding() throws { + let jsonScore = "{\"createdAt\":\"2021-03-15T02:24:47.841Z\",\"score\":5}" + guard let encoded = jsonScore.data(using: .utf8) else { + XCTFail("Shuld have created data") + return + } + XCTAssertNoThrow(try ParseCoding.jsonDecoder().decode(GameScore.self, from: encoded)) + } } From 5a68dd915da019f7975faefe07eb4af042486b19 Mon Sep 17 00:00:00 2001 From: Corey's iMac Date: Sun, 14 Mar 2021 20:47:41 -0400 Subject: [PATCH 14/14] nits --- Sources/ParseSwift/Types/ParseCloud.swift | 2 +- Sources/ParseSwift/Types/Query.swift | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/ParseSwift/Types/ParseCloud.swift b/Sources/ParseSwift/Types/ParseCloud.swift index 8382b88bf..078057bd3 100644 --- a/Sources/ParseSwift/Types/ParseCloud.swift +++ b/Sources/ParseSwift/Types/ParseCloud.swift @@ -83,7 +83,7 @@ extension ParseCloud { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: A block that will be called when logging out, completes or fails. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result)`. */ public func startJob(options: API.Options = [], callbackQueue: DispatchQueue = .main, diff --git a/Sources/ParseSwift/Types/Query.swift b/Sources/ParseSwift/Types/Query.swift index 689b8e05d..eb89e8cc8 100644 --- a/Sources/ParseSwift/Types/Query.swift +++ b/Sources/ParseSwift/Types/Query.swift @@ -859,7 +859,7 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a response of `Decodable` type to the query. + - returns: Returns a response of `Decodable` type. */ public func find(explain: Bool, hint: String? = nil, @@ -893,7 +893,7 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: The block to execute. - It should have the following argument signature: `(Result)`. + It should have the following argument signature: `(Result<[Decodable], ParseError>)`. */ public func find(explain: Bool, hint: String? = nil, @@ -929,7 +929,7 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a response of `Decodable` type to the query. + - returns: Returns a response of `Decodable` type. */ public func first(explain: Bool, hint: String? = nil, @@ -998,7 +998,7 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - - returns: Returns a response of `Decodable` type to the query. + - returns: Returns a response of `Decodable` type. */ public func count(explain: Bool, hint: String? = nil, @@ -1079,7 +1079,7 @@ extension Query: Queryable { - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of `.main`. - parameter completion: The block to execute. - It should have the following argument signature: `(Result<[ResultType], ParseError>)`. + It should have the following argument signature: `(Result<[ParseObject], ParseError>)`. - warning: This hasn't been tested thoroughly. */ public func aggregate(_ pipeline: AggregateType,