Skip to content

Commit e6457a4

Browse files
authored
fix: always sort JSON encoded keys (#318)
* fix: always sort JSON encoded keys * Enable more tests on Linux and Windows * more query tests * more tests * disable tests for linux and windows * Update CHANGELOG.md
1 parent b2a0d9c commit e6457a4

21 files changed

+124
-175
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22

33
### main
44

5-
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.0...main)
5+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.1...main)
66
* _Contributing to this repo? Add info about your change here to be included in the next release_
77

8+
### 3.1.1
9+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.0...3.1.1)
10+
11+
__Fixes__
12+
- Always sort keys when using the ParseEncoder as it can cause issues when trying to save ParseObject's that have children ([#318](https://github.com/parse-community/Parse-Swift/pull/318)), thanks to [Corey Baker](https://github.com/cbaker6).
13+
814
### 3.1.0
915
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.0.0...3.1.0)
1016

Sources/ParseSwift/Coding/ParseCoding.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extension ParseCoding {
2020
static func jsonEncoder() -> JSONEncoder {
2121
let encoder = JSONEncoder()
2222
encoder.dateEncodingStrategy = parseDateEncodingStrategy
23+
encoder.outputFormatting = .sortedKeys
2324
return encoder
2425
}
2526

Sources/ParseSwift/Coding/ParseEncoder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public struct ParseEncoder {
9595
let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: SkipKeys.none.keys())
9696
if let dateEncodingStrategy = dateEncodingStrategy {
9797
encoder.dateEncodingStrategy = dateEncodingStrategy
98+
encoder.outputFormatting = .sortedKeys
9899
}
99100
return try encoder.encodeObject(value,
100101
collectChildren: false,
@@ -114,6 +115,7 @@ public struct ParseEncoder {
114115
if let dateEncodingStrategy = dateEncodingStrategy {
115116
encoder.dateEncodingStrategy = dateEncodingStrategy
116117
}
118+
encoder.outputFormatting = .sortedKeys
117119
return try encoder.encodeObject(value,
118120
collectChildren: false,
119121
uniquePointer: nil,
@@ -135,6 +137,7 @@ public struct ParseEncoder {
135137
if let dateEncodingStrategy = dateEncodingStrategy {
136138
encoder.dateEncodingStrategy = dateEncodingStrategy
137139
}
140+
encoder.outputFormatting = .sortedKeys
138141
return try encoder.encodeObject(value,
139142
collectChildren: true,
140143
uniquePointer: try? value.toPointer(),
@@ -157,6 +160,7 @@ public struct ParseEncoder {
157160
if let dateEncodingStrategy = dateEncodingStrategy {
158161
encoder.dateEncodingStrategy = dateEncodingStrategy
159162
}
163+
encoder.outputFormatting = .sortedKeys
160164
return try encoder.encodeObject(value,
161165
collectChildren: collectChildren,
162166
uniquePointer: nil,

Sources/ParseSwift/ParseConstants.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010

1111
enum ParseConstants {
1212
static let sdk = "swift"
13-
static let version = "3.1.0"
13+
static let version = "3.1.1"
1414
static let fileManagementDirectory = "parse/"
1515
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
1616
static let fileManagementLibraryDirectory = "Library/"

Tests/ParseSwiftTests/IOS13Tests.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ class IOS13Tests: XCTestCase { // swiftlint:disable:this type_body_length
9090
wait(for: [expectation2], timeout: 20.0)
9191
}
9292

93-
#if !os(Linux) && !os(Android) && !os(Windows)
9493
func testSaveCommand() throws {
9594
let score = GameScore(points: 10)
9695
let className = score.className
@@ -101,7 +100,7 @@ class IOS13Tests: XCTestCase { // swiftlint:disable:this type_body_length
101100
XCTAssertEqual(command.method, API.Method.POST)
102101
XCTAssertNil(command.params)
103102

104-
let expected = "GameScore ({\"points\":10,\"player\":\"Jen\"})"
103+
let expected = "GameScore ({\"player\":\"Jen\",\"points\":10})"
105104
let decoded = score.debugDescription
106105
XCTAssertEqual(decoded, expected)
107106
}
@@ -125,13 +124,12 @@ class IOS13Tests: XCTestCase { // swiftlint:disable:this type_body_length
125124
return
126125
}
127126

128-
let expected = "{\"points\":10,\"player\":\"Jen\"}"
127+
let expected = "{\"player\":\"Jen\",\"points\":10}"
129128
let encoded = try ParseCoding.parseEncoder()
130129
.encode(body, collectChildren: false,
131130
objectsSavedBeforeThisOne: nil,
132131
filesSavedBeforeThisOne: nil).encoded
133132
let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))
134133
XCTAssertEqual(decoded, expected)
135134
}
136-
#endif
137135
}

Tests/ParseSwiftTests/ParseBytesTests.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class ParseBytesTests: XCTestCase {
3939
XCTAssertEqual(decoded, bytes)
4040
}
4141

42-
#if !os(Linux) && !os(Android) && !os(Windows)
4342
func testDebugString() {
4443
let bytes = ParseBytes(base64: "ZnJveW8=")
4544
let expected = "ParseBytes ({\"__type\":\"Bytes\",\"base64\":\"ZnJveW8=\"})"
@@ -63,5 +62,4 @@ class ParseBytesTests: XCTestCase {
6362
let bytes2 = ParseBytes(data: data)
6463
XCTAssertEqual(bytes2.description, expected)
6564
}
66-
#endif
6765
}

Tests/ParseSwiftTests/ParseCloudTests.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length
9999
XCTAssertEqual(decoded, expected, "\"functionJobName\" key should be skipped by ParseEncoder")
100100
}
101101

102-
#if !os(Linux) && !os(Android) && !os(Windows)
103102
func testDebugString() {
104103
let cloud = Cloud2(functionJobName: "test", customKey: "parse")
105104
let expected = "{\"customKey\":\"parse\",\"functionJobName\":\"test\"}"
@@ -111,7 +110,6 @@ class ParseCloudTests: XCTestCase { // swiftlint:disable:this type_body_length
111110
let expected = "{\"customKey\":\"parse\",\"functionJobName\":\"test\"}"
112111
XCTAssertEqual(cloud.description, expected)
113112
}
114-
#endif
115113

116114
func testCallFunctionCommand() throws {
117115
let cloud = Cloud(functionJobName: "test")

Tests/ParseSwiftTests/ParseConfigTests.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length
146146
XCTAssertNil(command.body)
147147
}
148148

149-
#if !os(Linux) && !os(Android) && !os(Windows)
150149
func testDebugString() {
151150
var config = Config()
152151
config.welcomeMessage = "Hello"
@@ -160,7 +159,6 @@ class ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length
160159
let expected = "{\"welcomeMessage\":\"Hello\"}"
161160
XCTAssertEqual(config.description, expected)
162161
}
163-
#endif
164162

165163
func testFetch() {
166164
userLogin()

Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,12 @@ class TestParseEncoder: XCTestCase {
6262
_testRoundTrip(of: address)
6363
}
6464

65-
#if !os(Linux) && !os(Android) && !os(Windows)
6665
func testEncodingTopLevelStructuredClass() {
6766
// Person is a class with multiple fields.
68-
let expectedJSON = "{\"name\":\"Johnny Appleseed\",\"email\":\"[email protected]\"}".data(using: .utf8)!
67+
let expectedJSON = "{\"email\":\"[email protected]\",\"name\":\"Johnny Appleseed\"}".data(using: .utf8)!
6968
let person = Person.testValue
7069
_testRoundTrip(of: person, expectedJSON: expectedJSON)
7170
}
72-
#endif
7371

7472
func testEncodingTopLevelStructuredSingleStruct() {
7573
// Numbers is a struct which encodes as an array through a single value container.
@@ -102,7 +100,7 @@ class TestParseEncoder: XCTestCase {
102100
_testRoundTrip(of: EnhancedBool.fileNotFound, expectedJSON: "null".data(using: .utf8)!)
103101
}
104102

105-
#if !os(Linux) && !os(Android) && !os(Windows)
103+
#if !os(Linux) && !os(Android) && !os(Windows)
106104
func testEncodingMultipleNestedContainersWithTheSameTopLevelKey() {
107105
struct Model: Codable, Equatable {
108106
let first: String
@@ -159,7 +157,6 @@ class TestParseEncoder: XCTestCase {
159157
}
160158
}
161159
#endif
162-
163160
/*
164161
func testEncodingConflictedTypeNestedContainersWithTheSameTopLevelKey() throws {
165162
struct Model: Encodable, Equatable {
@@ -202,13 +199,11 @@ class TestParseEncoder: XCTestCase {
202199
}*/
203200

204201
// MARK: - Output Formatting Tests
205-
#if !os(Linux) && !os(Android) && !os(Windows)
206202
func testEncodingOutputFormattingDefault() {
207-
let expectedJSON = "{\"name\":\"Johnny Appleseed\",\"email\":\"[email protected]\"}".data(using: .utf8)!
203+
let expectedJSON = "{\"email\":\"[email protected]\",\"name\":\"Johnny Appleseed\"}".data(using: .utf8)!
208204
let person = Person.testValue
209205
_testRoundTrip(of: person, expectedJSON: expectedJSON)
210206
}
211-
#endif
212207
/*
213208
func testEncodingOutputFormattingPrettyPrinted() {
214209
let expectedJSON = "{\n \"name\" : \"Johnny Appleseed\",\n \"email\" : \"[email protected]\"\n}".data(using: .utf8)!

Tests/ParseSwiftTests/ParseFileTests.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ class ParseFileTests: XCTestCase { // swiftlint:disable:this type_body_length
193193
XCTAssertEqual(parseFile1, parseFile2, "no urls, but localIds shoud be the same")
194194
}
195195

196-
#if !os(Linux) && !os(Android) && !os(Windows)
197196
func testDebugString() throws {
198197
guard let sampleData = "Hello World".data(using: .utf8) else {
199198
throw ParseError(code: .unknownError, message: "Should have converted to data")
@@ -203,11 +202,10 @@ class ParseFileTests: XCTestCase { // swiftlint:disable:this type_body_length
203202
metadata: ["Testing": "123"],
204203
tags: ["Hey": "now"])
205204
XCTAssertEqual(parseFile.debugDescription,
206-
"ParseFile ({\"name\":\"sampleData.txt\",\"__type\":\"File\"})")
205+
"ParseFile ({\"__type\":\"File\",\"name\":\"sampleData.txt\"})")
207206
XCTAssertEqual(parseFile.description,
208-
"ParseFile ({\"name\":\"sampleData.txt\",\"__type\":\"File\"})")
207+
"ParseFile ({\"__type\":\"File\",\"name\":\"sampleData.txt\"})")
209208
}
210-
#endif
211209

212210
func testSave() throws {
213211
guard let sampleData = "Hello World".data(using: .utf8) else {

0 commit comments

Comments
 (0)