From cf8ff557fca7552bb827214d4fe0c5a4fedcdb6c Mon Sep 17 00:00:00 2001 From: Corey Date: Thu, 7 Apr 2022 13:31:07 -0400 Subject: [PATCH] fix: improve codable's --- Sources/ParseSwift/Coding/AnyDecodable.swift | 2 +- Sources/ParseSwift/Coding/AnyEncodable.swift | 7 +- .../AnyCodableTests/AnyCodableTests.swift | 41 ++++- .../AnyCodableTests/AnyEncodableTests.swift | 143 +++++++++++++++++- 4 files changed, 179 insertions(+), 14 deletions(-) diff --git a/Sources/ParseSwift/Coding/AnyDecodable.swift b/Sources/ParseSwift/Coding/AnyDecodable.swift index 2fe699c20..e7bb1f77e 100755 --- a/Sources/ParseSwift/Coding/AnyDecodable.swift +++ b/Sources/ParseSwift/Coding/AnyDecodable.swift @@ -13,7 +13,7 @@ import Foundation let json = """ { "boolean": true, - "integer": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], diff --git a/Sources/ParseSwift/Coding/AnyEncodable.swift b/Sources/ParseSwift/Coding/AnyEncodable.swift index f10e32c0a..8be3368b0 100755 --- a/Sources/ParseSwift/Coding/AnyEncodable.swift +++ b/Sources/ParseSwift/Coding/AnyEncodable.swift @@ -12,7 +12,7 @@ import Foundation let dictionary: [String: AnyEncodable] = [ "boolean": true, - "integer": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], @@ -20,7 +20,8 @@ import Foundation "a": "alpha", "b": "bravo", "c": "charlie" - ] + ], + "null": nil ] let encoder = JSONEncoder() @@ -99,6 +100,8 @@ extension _AnyEncodable { try container.encode(array.map { AnyEncodable($0) }) case let dictionary as [String: Any?]: try container.encode(dictionary.mapValues { AnyEncodable($0) }) + case let encodable as Encodable: + try encodable.encode(to: encoder) default: let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "AnyEncodable value cannot be encoded") diff --git a/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift b/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift index f295d0ec2..f23ff6373 100755 --- a/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift +++ b/Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift @@ -2,6 +2,22 @@ import XCTest @testable import ParseSwift class AnyCodableTests: XCTestCase { + + struct SomeCodable: Codable { + var string: String + var int: Int + var bool: Bool + var hasUnderscore: String + + // swiftlint:disable:next nesting + enum CodingKeys: String, CodingKey { + case string + case int + case bool + case hasUnderscore = "has_underscore" + } + } + func testJSONDecoding() { guard let json = """ { @@ -42,9 +58,15 @@ class AnyCodableTests: XCTestCase { //Test has objective-c #if !os(Linux) && !os(Android) && !os(Windows) func testJSONEncoding() { + + let someCodable = AnyCodable(SomeCodable(string: "String", + int: 100, + bool: true, + hasUnderscore: "another string")) + let dictionary: [String: AnyCodable] = [ "boolean": true, - "integer": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], @@ -52,7 +74,9 @@ class AnyCodableTests: XCTestCase { "a": "alpha", "b": "bravo", "c": "charlie" - ] + ], + "someCodable": someCodable, + "null": nil ] do { let encoder = JSONEncoder() @@ -64,8 +88,8 @@ class AnyCodableTests: XCTestCase { } guard let expected = """ { - "boolean": true, - "integer": 1, + "boolean": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], @@ -73,7 +97,14 @@ class AnyCodableTests: XCTestCase { "a": "alpha", "b": "bravo", "c": "charlie" - } + }, + "someCodable": { + "string":"String", + "int":100, + "bool": true, + "has_underscore":"another string" + }, + "null": null } """.data(using: .utf8) else { XCTFail("Should unrap data to utf8") diff --git a/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift b/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift index b3c7dd30e..9ffa44ebc 100755 --- a/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift +++ b/Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift @@ -1,13 +1,35 @@ import XCTest @testable import ParseSwift -//Test has objective-c +// Test has objective-c #if !os(Linux) && !os(Android) && !os(Windows) class AnyEncodableTests: XCTestCase { + + struct SomeEncodable: Encodable { + var string: String + var int: Int + var bool: Bool + var hasUnderscore: String + + // swiftlint:disable:next nesting + enum CodingKeys: String, CodingKey { + case string + case int + case bool + case hasUnderscore = "has_underscore" + } + } + func testJSONEncoding() { + + let someEncodable = AnyEncodable(SomeEncodable(string: "String", + int: 100, + bool: true, + hasUnderscore: "another string")) + let dictionary: [String: AnyEncodable] = [ "boolean": true, - "integer": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], @@ -15,8 +37,11 @@ class AnyEncodableTests: XCTestCase { "a": "alpha", "b": "bravo", "c": "charlie" - ] + ], + "someCodable": someEncodable, + "null": nil ] + do { let encoder = JSONEncoder() let json = try encoder.encode(dictionary) @@ -27,8 +52,8 @@ class AnyEncodableTests: XCTestCase { } guard let expected = """ { - "boolean": true, - "integer": 1, + "boolean": 1, + "integer": 42, "double": 3.14159265358979323846, "string": "string", "array": [1, 2, 3], @@ -36,7 +61,14 @@ class AnyEncodableTests: XCTestCase { "a": "alpha", "b": "bravo", "c": "charlie" - } + }, + "someCodable": { + "string": "String", + "int": 100, + "bool": true, + "has_underscore": "another string" + }, + "null": null } """.data(using: .utf8) else { XCTFail("Should unrap data to utf8") @@ -52,5 +84,104 @@ class AnyEncodableTests: XCTestCase { XCTFail(error.localizedDescription) } } + + func testEncodeNSNumber() throws { + let dictionary: [String: NSNumber] = [ + "boolean": true, + "char": -127, + "int": -32767, + "short": -32767, + "long": -2147483647, + "longlong": -9223372036854775807, + "uchar": 255, + "uint": 65535, + "ushort": 65535, + "ulong": 4294967295, + "ulonglong": 18446744073709615, + "double": 3.141592653589793 + ] + + let encoder = JSONEncoder() + + let json = try encoder.encode(AnyEncodable(dictionary)) + guard let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else { + XCTFail("Should have unwrapped") + return + } + + let expected = """ + { + "boolean": 1, + "char": -127, + "int": -32767, + "short": -32767, + "long": -2147483647, + "longlong": -9223372036854775807, + "uchar": 255, + "uint": 65535, + "ushort": 65535, + "ulong": 4294967295, + "ulonglong": 18446744073709615, + "double": 3.141592653589793, + } + """.data(using: .utf8)! + // swiftlint:disable:next line_length + guard let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else { + XCTFail("Should have unwrapped") + return + } + + XCTAssertEqual(encodedJSONObject, expectedJSONObject) + XCTAssert(encodedJSONObject["boolean"] is Bool) + + XCTAssert(encodedJSONObject["char"] is Int8) + XCTAssert(encodedJSONObject["int"] is Int16) + XCTAssert(encodedJSONObject["short"] is Int32) + XCTAssert(encodedJSONObject["long"] is Int32) + XCTAssert(encodedJSONObject["longlong"] is Int64) + + XCTAssert(encodedJSONObject["uchar"] is UInt8) + XCTAssert(encodedJSONObject["uint"] is UInt16) + XCTAssert(encodedJSONObject["ushort"] is UInt32) + XCTAssert(encodedJSONObject["ulong"] is UInt32) + XCTAssert(encodedJSONObject["ulonglong"] is UInt64) + + XCTAssert(encodedJSONObject["double"] is Double) + } + + func testStringInterpolationEncoding() throws { + let dictionary: [String: AnyEncodable] = [ + "boolean": "\(true)", + "integer": "\(42)", + "double": "\(3.141592653589793)", + "string": "\("string")", + "array": "\([1, 2, 3])" + ] + + let encoder = JSONEncoder() + + let json = try encoder.encode(dictionary) + guard let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else { + XCTFail("Should have unwrapped") + return + } + + let expected = """ + { + "boolean": "true", + "integer": "42", + "double": "3.141592653589793", + "string": "string", + "array": "[1, 2, 3]", + } + """.data(using: .utf8)! + // swiftlint:disable:next line_length + guard let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else { + XCTFail("Should have unwrapped") + return + } + + XCTAssertEqual(encodedJSONObject, expectedJSONObject) + } } #endif