From ca096b5f5b4c6392cd22c562c3755fbd01e89ffc Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 10 Jan 2021 17:23:00 -0500 Subject: [PATCH] Bug fix: issue when encoding objects that are already saved (#48) * Bug fix: issue when encoding objects that are already saved * Add test cases to detect if ParseObject body encoding breaks * Add dates to ensure skipKeys doesn't break * codecov patch set back to auto --- .codecov.yml | 2 +- Sources/ParseSwift/Coding/ParseEncoder.swift | 4 +- .../ParseSwift/LiveQuery/ParseLiveQuery.swift | 6 +- .../ParseObjectBatchTests.swift | 62 +++++++++++++++++++ Tests/ParseSwiftTests/ParseObjectTests.swift | 34 ++++++++-- 5 files changed, 99 insertions(+), 9 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 4bb4f7eb6..0783c91b4 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -5,7 +5,7 @@ coverage: status: patch: default: - target: 69 + target: auto changes: false project: default: diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 04733a5a5..600f686a4 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -262,7 +262,9 @@ private class _ParseEncoder: JSONEncoder, Encoder { throw ParseError(code: .unknownError, message: "Found a circular dependency when encoding.") } self.uniqueObjects.insert(object) - if !self.collectChildren { + if !self.collectChildren && codingPath.count > 0 { + valueToEncode = value + } else if !self.collectChildren { valueToEncode = value.toPointer() } } else { diff --git a/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift b/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift index d6a10fd51..ca00320c4 100644 --- a/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift +++ b/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift @@ -683,7 +683,7 @@ extension ParseLiveQuery { } } -// MARK: Query - Subscribe +// MARK: ParseLiveQuery - Subscribe @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Query { /** @@ -728,7 +728,7 @@ public extension Query { } } -// MARK: Query - Unsubscribe +// MARK: ParseLiveQuery - Unsubscribe @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Query { /** @@ -768,7 +768,7 @@ public extension Query { } } -// MARK: Query - Update +// MARK: ParseLiveQuery - Update @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Query { /** diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index ef02c23d8..56149d946 100644 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -52,6 +52,35 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le try? ParseStorage.shared.deleteAll() } + func testSaveAllCommand() throws { + let score = GameScore(score: 10) + let score2 = GameScore(score: 20) + + var scoreOnServer = score + scoreOnServer.objectId = "yarr" + scoreOnServer.createdAt = Date() + scoreOnServer.updatedAt = scoreOnServer.createdAt + scoreOnServer.ACL = nil + + var scoreOnServer2 = score2 + scoreOnServer2.objectId = "yolo" + scoreOnServer2.createdAt = Date() + scoreOnServer2.updatedAt = scoreOnServer2.createdAt + scoreOnServer2.ACL = nil + + let objects = [score, score2] + let commands = objects.map { $0.saveCommand() } + let body = BatchCommand(requests: commands) + // swiftlint:disable:next line_length + let expected = "{\"requests\":[{\"path\":\"\\/classes\\/GameScore\",\"method\":\"POST\",\"body\":{\"score\":10}},{\"path\":\"\\/classes\\/GameScore\",\"method\":\"POST\",\"body\":{\"score\":20}}]}" + let encoded = try ParseCoding.parseEncoder() + .encode(body, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = String(data: encoded, encoding: .utf8) + XCTAssertEqual(decoded, expected) + } + func testSaveAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity let score = GameScore(score: 10) let score2 = GameScore(score: 20) @@ -235,6 +264,39 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le } } + func testUpdateAllCommand() throws { + var score = GameScore(score: 10) + var score2 = GameScore(score: 20) + + score.objectId = "yarr" + score.createdAt = Date() + score.updatedAt = Date() + score2.objectId = "yolo" + score2.createdAt = Date() + score2.updatedAt = Date() + + let objects = [score, score2] + let initialCommands = objects.map { $0.saveCommand() } + let commands = initialCommands.compactMap { (command) -> API.Command? in + let path = ParseConfiguration.mountPath + command.path.urlComponent + guard let body = command.body else { + return nil + } + return API.Command(method: command.method, path: .any(path), + body: body, mapper: command.mapper) + } + let body = BatchCommand(requests: commands) + // swiftlint:disable:next line_length + let expected = "{\"requests\":[{\"path\":\"\\/1\\/classes\\/GameScore\\/yarr\",\"method\":\"PUT\",\"body\":{\"score\":10}},{\"path\":\"\\/1\\/classes\\/GameScore\\/yolo\",\"method\":\"PUT\",\"body\":{\"score\":20}}]}" + + let encoded = try ParseCoding.parseEncoder() + .encode(body, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = String(data: encoded, encoding: .utf8) + XCTAssertEqual(decoded, expected) + } + func testUpdateAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity var score = GameScore(score: 10) score.objectId = "yarr" diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index e0a915f63..045092991 100644 --- a/Tests/ParseSwiftTests/ParseObjectTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectTests.swift @@ -461,7 +461,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length self.fetchAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main) } - func testSaveCommand() { + func testSaveCommand() throws { let score = GameScore(score: 10) let className = score.className @@ -470,23 +470,49 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length XCTAssertEqual(command.path.urlComponent, "/classes/\(className)") XCTAssertEqual(command.method, API.Method.POST) XCTAssertNil(command.params) - XCTAssertNotNil(command.body) XCTAssertNotNil(command.data) + + guard let body = command.body else { + XCTFail("Should be able to unwrap") + return + } + + let expected = "{\"score\":10,\"player\":\"Jen\"}" + let encoded = try ParseCoding.parseEncoder() + .encode(body, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = String(data: encoded, encoding: .utf8) + XCTAssertEqual(decoded, expected) } - func testUpdateCommand() { + func testUpdateCommand() throws { var score = GameScore(score: 10) let className = score.className let objectId = "yarr" score.objectId = objectId + score.createdAt = Date() + score.updatedAt = Date() let command = score.saveCommand() XCTAssertNotNil(command) XCTAssertEqual(command.path.urlComponent, "/classes/\(className)/\(objectId)") XCTAssertEqual(command.method, API.Method.PUT) XCTAssertNil(command.params) - XCTAssertNotNil(command.body) XCTAssertNotNil(command.data) + + guard let body = command.body else { + XCTFail("Should be able to unwrap") + return + } + + let expected = "{\"score\":10,\"player\":\"Jen\"}" + let encoded = try ParseCoding.parseEncoder() + .encode(body, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = String(data: encoded, encoding: .utf8) + XCTAssertEqual(decoded, expected) } func testSave() { // swiftlint:disable:this function_body_length