-
-
Notifications
You must be signed in to change notification settings - Fork 136
Improve tests and fix encoding of NSNumber #84
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,8 @@ extension _AnyEncodable { | |
#if canImport(Foundation) | ||
case is NSNull: | ||
try container.encodeNil() | ||
case let number as NSNumber: | ||
try encode(nsnumber: number, into: &container) | ||
#endif | ||
case is Void: | ||
try container.encodeNil() | ||
|
@@ -87,8 +89,6 @@ extension _AnyEncodable { | |
case let string as String: | ||
try container.encode(string) | ||
#if canImport(Foundation) | ||
case let number as NSNumber: | ||
try encode(nsnumber: number, into: &container) | ||
case let date as Date: | ||
try container.encode(date) | ||
case let url as URL: | ||
|
@@ -108,28 +108,24 @@ extension _AnyEncodable { | |
|
||
#if canImport(Foundation) | ||
private func encode(nsnumber: NSNumber, into container: inout SingleValueEncodingContainer) throws { | ||
switch Character(Unicode.Scalar(UInt8(nsnumber.objCType.pointee))) { | ||
case "B": | ||
switch UInt32(nsnumber.objCType.pointee) { | ||
case cpp_or_c99_bool_objc_encoding, char_objc_encoding, unsigned_char_objc_encoding: | ||
try container.encode(nsnumber.boolValue) | ||
case "c": | ||
try container.encode(nsnumber.int8Value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this case is now mapped to a boolean |
||
case "s": | ||
case short_objc_encoding: | ||
try container.encode(nsnumber.int16Value) | ||
case "i", "l": | ||
case int_objc_encoding, long_objc_encoding: | ||
try container.encode(nsnumber.int32Value) | ||
case "q": | ||
case long_long_objc_encoding: | ||
try container.encode(nsnumber.int64Value) | ||
case "C": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this case is now mapped to a boolean |
||
try container.encode(nsnumber.uint8Value) | ||
case "S": | ||
case unsigned_short_objc_encoding: | ||
try container.encode(nsnumber.uint16Value) | ||
case "I", "L": | ||
case unsigned_int_objc_encoding, unsigned_long_objc_encoding: | ||
try container.encode(nsnumber.uint32Value) | ||
case "Q": | ||
case unsigned_long_long_objc_encoding: | ||
try container.encode(nsnumber.uint64Value) | ||
case "f": | ||
case float_objc_encoding: | ||
try container.encode(nsnumber.floatValue) | ||
case "d": | ||
case double_objc_encoding: | ||
try container.encode(nsnumber.doubleValue) | ||
default: | ||
let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "NSNumber cannot be encoded because its type is not handled") | ||
|
@@ -289,3 +285,21 @@ extension AnyEncodable: Hashable { | |
} | ||
} | ||
} | ||
|
||
|
||
#if canImport(Foundation) | ||
// Types encodings: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html | ||
private let cpp_or_c99_bool_objc_encoding = "B".unicodeScalars.first?.value | ||
private let char_objc_encoding = "c".unicodeScalars.first?.value | ||
private let short_objc_encoding = "s".unicodeScalars.first?.value | ||
private let int_objc_encoding = "i".unicodeScalars.first?.value | ||
private let long_objc_encoding = "l".unicodeScalars.first?.value | ||
private let long_long_objc_encoding = "q".unicodeScalars.first?.value | ||
private let unsigned_char_objc_encoding = "C".unicodeScalars.first?.value | ||
private let unsigned_short_objc_encoding = "S".unicodeScalars.first?.value | ||
private let unsigned_int_objc_encoding = "I".unicodeScalars.first?.value | ||
private let unsigned_long_objc_encoding = "L".unicodeScalars.first?.value | ||
private let unsigned_long_long_objc_encoding = "Q".unicodeScalars.first?.value | ||
private let float_objc_encoding = "f".unicodeScalars.first?.value | ||
private let double_objc_encoding = "d".unicodeScalars.first?.value | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,10 +20,12 @@ class AnyEncodableTests: XCTestCase { | |
func testJSONEncoding() throws { | ||
|
||
let someEncodable = AnyEncodable(SomeEncodable(string: "String", int: 100, bool: true, hasUnderscore: "another string")) | ||
|
||
let nsNumber = AnyEncodable(1 as NSNumber) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
|
||
let dictionary: [String: AnyEncodable] = [ | ||
"boolean": true, | ||
"integer": 42, | ||
"nsNumber": nsNumber, | ||
"double": 3.141592653589793, | ||
"string": "string", | ||
"array": [1, 2, 3], | ||
|
@@ -35,11 +37,8 @@ class AnyEncodableTests: XCTestCase { | |
"someCodable": someEncodable, | ||
"null": nil | ||
] | ||
let json = try JSONEncoder().encode(dictionary) | ||
|
||
let encoder = JSONEncoder() | ||
|
||
let json = try encoder.encode(dictionary) | ||
let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as! NSDictionary | ||
|
||
let expected = """ | ||
{ | ||
|
@@ -53,6 +52,7 @@ class AnyEncodableTests: XCTestCase { | |
"b": "bravo", | ||
"c": "charlie" | ||
}, | ||
"nsNumber": 1, | ||
"someCodable": { | ||
"string":"String", | ||
"int":100, | ||
|
@@ -61,10 +61,8 @@ class AnyEncodableTests: XCTestCase { | |
}, | ||
"null": null | ||
} | ||
""".data(using: .utf8)! | ||
let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as! NSDictionary | ||
|
||
XCTAssertEqual(encodedJSONObject, expectedJSONObject) | ||
""" | ||
try XCTAssertJsonAreIdentical(json, expected) | ||
} | ||
|
||
func testEncodeNSNumber() throws { | ||
|
@@ -83,10 +81,7 @@ class AnyEncodableTests: XCTestCase { | |
"double": 3.141592653589793, | ||
] | ||
|
||
let encoder = JSONEncoder() | ||
|
||
let json = try encoder.encode(AnyEncodable(dictionary)) | ||
let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as! NSDictionary | ||
let json = try JSONEncoder().encode(AnyEncodable(dictionary)) | ||
|
||
let expected = """ | ||
{ | ||
|
@@ -103,25 +98,8 @@ class AnyEncodableTests: XCTestCase { | |
"ulonglong": 18446744073709615, | ||
"double": 3.141592653589793, | ||
} | ||
""".data(using: .utf8)! | ||
let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as! NSDictionary | ||
|
||
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) | ||
Comment on lines
-108
to
-124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed this part that is not testing decoding |
||
""" | ||
try XCTAssertJsonAreIdentical(json, expected) | ||
} | ||
|
||
func testStringInterpolationEncoding() throws { | ||
|
@@ -132,11 +110,7 @@ class AnyEncodableTests: XCTestCase { | |
"string": "\("string")", | ||
"array": "\([1, 2, 3])", | ||
] | ||
|
||
let encoder = JSONEncoder() | ||
|
||
let json = try encoder.encode(dictionary) | ||
let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as! NSDictionary | ||
let json = try JSONEncoder().encode(dictionary) | ||
|
||
let expected = """ | ||
{ | ||
|
@@ -146,9 +120,38 @@ class AnyEncodableTests: XCTestCase { | |
"string": "string", | ||
"array": "[1, 2, 3]", | ||
} | ||
""".data(using: .utf8)! | ||
let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as! NSDictionary | ||
""" | ||
|
||
XCTAssertEqual(encodedJSONObject, expectedJSONObject) | ||
try XCTAssertJsonAreIdentical(json, expected) | ||
} | ||
} | ||
|
||
|
||
|
||
func XCTAssertJsonAreIdentical(_ expression1: String, _ expression2: String, options: JSONSerialization.WritingOptions? = nil) throws { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Helper functions to test that two serialized JSON (either |
||
let data = try XCTUnwrap(expression1.data(using: .utf8)) | ||
try XCTAssertJsonAreIdentical(data, expression2, options: options) | ||
} | ||
|
||
func XCTAssertJsonAreIdentical(_ expression1: String, _ expression2: Data, options: JSONSerialization.WritingOptions? = nil) throws { | ||
let data = try XCTUnwrap(expression1.data(using: .utf8)) | ||
try XCTAssertJsonAreIdentical(data, expression2, options: options) | ||
} | ||
|
||
func XCTAssertJsonAreIdentical(_ expression1: Data, _ expression2: String, options: JSONSerialization.WritingOptions? = nil) throws { | ||
let data = try XCTUnwrap(expression2.data(using: .utf8)) | ||
try XCTAssertJsonAreIdentical(expression1, data, options: options) | ||
} | ||
|
||
func XCTAssertJsonAreIdentical(_ expression1: Data, _ expression2: Data, options: JSONSerialization.WritingOptions? = nil) throws { | ||
var defaultOptions: JSONSerialization.WritingOptions = [] | ||
if #available(iOS 11.0, *) { | ||
defaultOptions = [.sortedKeys, .prettyPrinted] | ||
} else { | ||
defaultOptions = [.prettyPrinted] | ||
} | ||
XCTAssertEqual( | ||
String(data: try JSONSerialization.data(withJSONObject: try JSONSerialization.jsonObject(with: expression1), options: options ?? defaultOptions), encoding: .utf8), | ||
String(data: try JSONSerialization.data(withJSONObject: try JSONSerialization.jsonObject(with: expression2), options: options ?? defaultOptions), encoding: .utf8) | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for applications where performance matters, this change should help make the code run faster.