diff --git a/Tests/DictionaryCodingTests/DictionaryDecodingTests.swift b/Tests/DictionaryCodingTests/DictionaryDecodingTests.swift index 63467de..24f715b 100644 --- a/Tests/DictionaryCodingTests/DictionaryDecodingTests.swift +++ b/Tests/DictionaryCodingTests/DictionaryDecodingTests.swift @@ -2,37 +2,54 @@ import XCTest @testable import DictionaryCoding class DictionaryDecodingTests: XCTestCase { - - func testDecodingAllTheTypes() throws { - let encoded : [String:Any] = ["uint32": 123456, "data": "dGVzdA==", "int16": -12345, "int64": -123456789, "uint8": 123, "date": 123456.789, "uint": 123456, "int": -123456, "int8": -123, "bool": 1, "int32": -123456, "double": 12345.6789, "uint64": 123456789, "float": 123.456, "uint16": 12345, "string": "blah"] - - let decoder = DictionaryDecoder() - let decoded = try decoder.decode(AllTheTypes.self, from: encoded) + var sut: DictionaryDecoder! + + override func setUp() { + sut = DictionaryDecoder() + } + + override func tearDown() { + sut = nil + } + + func test_decoding_allTheTypes_shouldSucceed() throws { + // given + let encoded: [String: Any] = ["uint32": 123456, "data": "dGVzdA==", "int16": -12345, "int64": -123456789, "uint8": 123, "date": 123456.789, "uint": 123456, "int": -123456, "int8": -123, "bool": 1, "int32": -123456, "double": 12345.6789, "uint64": 123456789, "float": 123.456, "uint16": 12345, "string": "blah"] + // when + let decoded = try sut.decode(AllTheTypes.self, from: encoded) + + // then XCTAssertEqual(decoded.string, "blah") XCTAssertEqual(decoded.int, -123456) XCTAssertEqual(decoded.int8, -123) XCTAssertEqual(decoded.int16, -12345) XCTAssertEqual(decoded.int32, -123456) XCTAssertEqual(decoded.int64, -123456789) + XCTAssertEqual(decoded.data, "test".data(using: .utf8)) } - func testDecodingNSDictionary() throws { - let pet1 : NSMutableDictionary = NSMutableDictionary() + func test_decoding_NSDictionary_shouldSucceed() throws { + // given + let pet1 = NSMutableDictionary() pet1["name"] = "Morven" - let pet2 : NSMutableDictionary = NSMutableDictionary() + + let pet2 = NSMutableDictionary() pet2["name"] = "Rebus" - let pets : NSMutableArray = NSMutableArray() + + let pets = NSMutableArray() pets.add(pet1) pets.add(pet2) - let dict : NSMutableDictionary = NSMutableDictionary() + + let dict = NSMutableDictionary() dict["name"] = "Sam" dict["age"] = 48 dict["pets"] = pets - - let decoder = DictionaryDecoder() - let decoded = try decoder.decode(Person.self, from: dict) - + + // when + let decoded = try sut.decode(Person.self, from: dict) + + // then XCTAssertEqual(decoded.name, "Sam") XCTAssertEqual(decoded.age, 48) XCTAssertEqual(decoded.pets.count, 2) @@ -40,12 +57,14 @@ class DictionaryDecodingTests: XCTestCase { XCTAssertEqual(decoded.pets[1].name, "Rebus") } - func testDecodingCFDictionary() throws { - let dict = [ "name" : "Sam", "age" : 48, "pets" : [ ["name" : "Morven"], ["name" : "Rebus"]]] as CFDictionary - - let decoder = DictionaryDecoder() - let decoded = try decoder.decode(Person.self, from: dict) - + func test_decoding_CFDictionary_shouldSucceed() throws { + // given + let dict = ["name": "Sam", "age": 48, "pets": [["name": "Morven"], ["name": "Rebus"]]] as CFDictionary + + // when + let decoded = try sut.decode(Person.self, from: dict) + + // then XCTAssertEqual(decoded.name, "Sam") XCTAssertEqual(decoded.age, 48) XCTAssertEqual(decoded.pets.count, 2) @@ -53,12 +72,14 @@ class DictionaryDecodingTests: XCTestCase { XCTAssertEqual(decoded.pets[1].name, "Rebus") } - func testDecodingSwiftDictionary() throws { - let dict : [String:Any] = [ "name" : "Sam", "age" : 48, "pets" : [ ["name" : "Morven"], ["name" : "Rebus"]]] - - let decoder = DictionaryDecoder() - let decoded = try decoder.decode(Person.self, from: dict) - + func test_decoding_swiftDictionary_shouldSucceed() throws { + // given + let dict: [String: Any] = ["name": "Sam", "age": 48, "pets": [["name": "Morven"], ["name": "Rebus"]]] + + // when + let decoded = try sut.decode(Person.self, from: dict) + + // then XCTAssertEqual(decoded.name, "Sam") XCTAssertEqual(decoded.age, 48) XCTAssertEqual(decoded.pets.count, 2) @@ -66,35 +87,44 @@ class DictionaryDecodingTests: XCTestCase { XCTAssertEqual(decoded.pets[1].name, "Rebus") } - func testFailureWithMissingKeys() { - let dict = [ "name" : "Sam", "age" : 48 ] as NSDictionary - let decoder = DictionaryDecoder() - XCTAssertThrowsError(try decoder.decode(Person.self, from: dict)) + func test_decoding_withMissingKeys_shouldFail() { + // given + let dict = ["name": "Sam", "age": 48] as NSDictionary + + // when/then + XCTAssertThrowsError(try sut.decode(Person.self, from: dict)) } - func testDecodingOptionalValues() throws { - // the dictionary is missing some keys, but decoding shouldn't fail - // as they correspond to properties that are optional in the struct - - let dict : [String:Any] = [ "name" : "Sam" ] - - let decoder = DictionaryDecoder() - let decoded = try decoder.decode(Test.self, from: dict) - + // the dictionary is missing some keys, but decoding shouldn't fail + // as they correspond to properties that are optional in the struct + func test_decoding_missingKeysOfOptionalValues_shouldSucceed() throws { + // given + struct Test: Codable { + let name: String + let label: String? + } + + let dict: [String: Any] = ["name": "Sam"] + + // when + let decoded = try sut.decode(Test.self, from: dict) + + // then XCTAssertEqual(decoded.name, "Sam") XCTAssertNil(decoded.label) } - func testDecodingWithStandardDefaults() throws { - // the dictionary is missing some keys, but they can be filled in - // using default values if we set the missingValue strategy to .useDefault - let dict : [String:Any] = [:] - - let decoder = DictionaryDecoder() - decoder.missingValueDecodingStrategy = .useStandardDefault - - let decoded = try decoder.decode(AllTheTypes.self, from: dict) - + // the dictionary is missing some keys, but they can be filled in + // using default values if we set the missingValue strategy to .useDefault + func test_decoding_withStandardDefaults_shouldSucceed() throws { + // given + let dict: [String: Any] = [:] + + // when + sut.missingValueDecodingStrategy = .useStandardDefault + let decoded = try sut.decode(AllTheTypes.self, from: dict) + + // then XCTAssertEqual(decoded.string, "") XCTAssertEqual(decoded.int, 0) XCTAssertEqual(decoded.int8, 0) @@ -109,28 +139,29 @@ class DictionaryDecodingTests: XCTestCase { XCTAssertEqual(decoded.bool, false) XCTAssertEqual(decoded.float, 0) XCTAssertEqual(decoded.double, 0) + XCTAssertEqual(decoded.data, Data()) } - func testDecodingWithDefaults() throws { - // the dictionary is missing some keys, but they can be filled in - // using default values if we set the missingValue strategy to .useDefault - struct Test : Codable { - let name : String - let label : String - let age : Int - let flag : Bool - let value : Double + // the dictionary is missing some keys, but they can be filled in + // using default values if we set the missingValue strategy to .useDefault + func test_decoding_withDefaults_shouldSucceed() throws { + // given + struct Test: Codable { + let name: String + let label: String + let age: Int + let flag: Bool + let value: Double } - - let dict : [String:Any] = [ "name" : "Sam" ] - - let decoder = DictionaryDecoder() - - let defaults : [String:Any] = [ "String" : "default", "Int" : 123, "Bool" : true, "Double" : 123.456 ] - decoder.missingValueDecodingStrategy = .useDefault(defaults: defaults) - - let decoded = try decoder.decode(Test.self, from: dict) - + + let dict: [String: Any] = ["name": "Sam"] + let defaults: [String: Any] = ["String": "default", "Int": 123, "Bool": true, "Double": 123.456] + + // when + sut.missingValueDecodingStrategy = .useDefault(defaults: defaults) + let decoded = try sut.decode(Test.self, from: dict) + + // then XCTAssertEqual(decoded.name, "Sam") XCTAssertEqual(decoded.label, "default") XCTAssertEqual(decoded.age, 123) @@ -138,96 +169,130 @@ class DictionaryDecodingTests: XCTestCase { XCTAssertEqual(decoded.value, 123.456) } - func testDecodingStringFromURL() throws { - // if we're expecting a string, but are given a URL, we should be able to cope - struct Test : Decodable { - let value : String + // if we're expecting a string, but are given a URL, we should be able to cope + func test_decoding_stringFromURL_shouldSucceed() throws { + // given + struct JustString: Decodable { + let value: String } - - let decoder = DictionaryDecoder() - let encoded1 : [String:Any] = ["value" : URL(fileURLWithPath: "/path")] - let decoded1 = try decoder.decode(Test.self, from: encoded1) - XCTAssertEqual(decoded1.value, "file:///path") + let encoded1: [String: Any] = ["value": URL(fileURLWithPath: "/path")] + let encoded2: [String: Any] = ["value": NSURL(fileURLWithPath: "/path")] + + // when + let decoded1 = try sut.decode(JustString.self, from: encoded1) + let decoded2 = try sut.decode(JustString.self, from: encoded2) - let encoded2 : [String:Any] = ["value" : NSURL(fileURLWithPath: "/path")] - let decoded2 = try decoder.decode(Test.self, from: encoded2) + // then + XCTAssertEqual(decoded1.value, "file:///path") XCTAssertEqual(decoded2.value, "file:///path") } - func testDecodingStringFromUUID() throws { - // if we're expecting a string, but are given a UUID, we should be able to cope - struct Test : Decodable { - let value : String + func test_decoding_urlFromString_shouldSucceed() throws { + // given + struct JustURL: Decodable { + let value: URL } - let decoder = DictionaryDecoder() + let encoded: [String: Any] = ["value": URL(fileURLWithPath: "/path").absoluteURL] + + // when + let decoded = try sut.decode(JustURL.self, from: encoded) + + // then + XCTAssertEqual(decoded.value, URL(string: "file:///path")) + } + + // if we're expecting a string, but are given a UUID, we should be able to cope + func test_decoding_stringFromUUID_shouldSucceed() throws { + // given + struct JustString: Decodable { + let value: String + } let uuid = UUID() - let encoded : [String:Any] = ["value" : uuid] - let decoded = try decoder.decode(Test.self, from: encoded) + let encoded: [String: Any] = ["value": uuid] + + // when + let decoded = try sut.decode(JustString.self, from: encoded) + + // then XCTAssertEqual(decoded.value, uuid.uuidString) } - func testDecodingUUID() throws { - // if we're expecting a UUID, but are given a String or a CFUUID, we should be able to cope - struct Test : Decodable { - let value : UUID + // if we're expecting a UUID, but are given a String or a CFUUID, we should be able to cope + func test_decoding_uuidFromVariousUUIDTypes_shouldSucceed() throws { + // given + struct JustUUID: Decodable { + let value: UUID } - let decoder = DictionaryDecoder() - let uuid = UUID() - let encoded1 : [String:Any] = ["value" : uuid] - let decoded1 = try decoder.decode(Test.self, from: encoded1) - XCTAssertEqual(decoded1.value, uuid) + let encoded1: [String: Any] = ["value": uuid] + let encoded2: [String: Any] = ["value": uuid.uuidString] + let encoded3: [String: Any] = ["value": CFUUIDCreateFromString(nil, uuid.uuidString as CFString)!] - let encoded2 : [String:Any] = ["value" : uuid.uuidString] - let decoded2 = try decoder.decode(Test.self, from: encoded2) - XCTAssertEqual(decoded2.value, uuid) + // when + let decoded1 = try sut.decode(JustUUID.self, from: encoded1) + let decoded2 = try sut.decode(JustUUID.self, from: encoded2) + let decoded3 = try sut.decode(JustUUID.self, from: encoded3) - let encoded3 : [String:Any] = ["value" : CFUUIDCreateFromString(nil, uuid.uuidString as CFString)!] - let decoded3 = try decoder.decode(Test.self, from: encoded3) + // then + XCTAssertEqual(decoded1.value, uuid) + XCTAssertEqual(decoded2.value, uuid) XCTAssertEqual(decoded3.value, uuid) + } - // test for crashes when given other slightly random types... - XCTAssertThrowsError(try decoder.decode(Test.self, from: ["value" : 123])) - XCTAssertThrowsError(try decoder.decode(Test.self, from: ["value" : 123.456])) - XCTAssertThrowsError(try decoder.decode(Test.self, from: ["value" : true])) - XCTAssertThrowsError(try decoder.decode(Test.self, from: ["value" : URL(fileURLWithPath: "/test")])) + // test for crashes when given other slightly random types... + func test_decoding_uuidFromUnsupportedTypes_shouldFail() throws { + // given + struct JustUUID: Decodable { + let value: UUID + } + + // when/then + XCTAssertThrowsError(try sut.decode(JustUUID.self, from: ["value": 123])) + XCTAssertThrowsError(try sut.decode(JustUUID.self, from: ["value": 123.456])) + XCTAssertThrowsError(try sut.decode(JustUUID.self, from: ["value": true])) + XCTAssertThrowsError(try sut.decode(JustUUID.self, from: ["value": URL(fileURLWithPath: "/test")])) } - func testDecodingURL() throws { - // if we're expecting a URL, we should be able to cope with getting a string, URL or NSURL - // if we're expecting a UUID, but are given a String or a CFUUID, we should be able to cope - struct Test : Decodable { - let value : URL + // if we're expecting a URL, we should be able to cope with getting a string, URL or NSURL + // if we're expecting a UUID, but are given a String or a CFUUID, we should be able to cope + func test_decoding_urlFromVariousTypes_shouldSucceed() throws { + // given + struct JustURL: Decodable { + let value: URL } - let decoder = DictionaryDecoder() - - let url = URL(string: "http://elegantchaos.com")! - let decoded1 = try decoder.decode(Test.self, from: ["value" : url]) - XCTAssertEqual(decoded1.value, url) + let url = URL(fileURLWithPath: "/test") - let decoded2 = try decoder.decode(Test.self, from: ["value" : url.absoluteString]) - XCTAssertEqual(decoded2.value, url) + // when + let decoded1 = try sut.decode(JustURL.self, from: ["value": url]) + let decoded2 = try sut.decode(JustURL.self, from: ["value": url.absoluteString]) + let decoded3 = try sut.decode(JustURL.self, from: ["value": NSURL(string: url.absoluteString)!]) - let decoded3 = try decoder.decode(Test.self, from: ["value" : NSURL(string: url.absoluteString)!]) + // then + XCTAssertEqual(decoded1.value, url) + XCTAssertEqual(decoded2.value, url) XCTAssertEqual(decoded3.value, url) } - - static var allTests = [ - ("testDecodingAllTheTypes", testDecodingAllTheTypes), - ("testDecodingNSDictionary", testDecodingNSDictionary), - ("testDecodingCFDictionary", testDecodingCFDictionary), - ("testFailureWithMissingKeys", testFailureWithMissingKeys), - ("testDecodingOptionalValues", testDecodingOptionalValues), - ("testDecodingWithDefaults", testDecodingWithDefaults), - ("testDecodingStringFromURL", testDecodingStringFromURL), - ("testDecodingStringFromUUID", testDecodingStringFromUUID), - ("testDecodingUUID", testDecodingUUID), - ("testDecodingURL", testDecodingURL), - ] + func test_decoding_dataFromVariousTypes_shouldSucceed() throws { + // given + struct JustData: Codable { + let data: Data + } + + let encoded1: [String: Any] = ["data": "dGVzdA=="] + let encoded2: [String: Any] = ["data": "test2".data(using: .utf8)!] + + // when + let decoded1 = try sut.decode(JustData.self, from: encoded1) + let decoded2 = try sut.decode(JustData.self, from: encoded2) + + // then + XCTAssertEqual(decoded1.data, "test".data(using: .utf8)) + XCTAssertEqual(decoded2.data, "test2".data(using: .utf8)) + } } diff --git a/Tests/DictionaryCodingTests/DictionaryEncodingTests.swift b/Tests/DictionaryCodingTests/DictionaryEncodingTests.swift index f962c86..e3bbc8a 100644 --- a/Tests/DictionaryCodingTests/DictionaryEncodingTests.swift +++ b/Tests/DictionaryCodingTests/DictionaryEncodingTests.swift @@ -1,123 +1,55 @@ import XCTest @testable import DictionaryCoding -struct Pet : Codable, Equatable { - let name : String +struct Pet: Codable, Equatable { + let name: String } -struct Person : Codable, Equatable { - let name : String - let age : Int - let pets : [Pet] +struct Person: Codable, Equatable { + let name: String + let age: Int + let pets: [Pet] } -struct Test : Codable { - let name : String - let label : String? -} - -struct AllTheTypes : Codable { - let string : String - let int : Int - let int8 : Int8 - let int16 : Int16 - let int32 : Int32 - let int64 : Int64 - let uint : UInt - let uint8 : UInt8 - let uint16 : UInt16 - let uint32 : UInt32 - let uint64 : UInt64 - let float : Float - let double : Double - let bool : Bool - let date : Date - let data : Data -} - -struct JustDate : Codable { - let date : Date -} - -struct JustData : Codable { - let data : Data +struct AllTheTypes: Codable { + let string: String + let int: Int + let int8: Int8 + let int16: Int16 + let int32: Int32 + let int64: Int64 + let uint: UInt + let uint8: UInt8 + let uint16: UInt16 + let uint32: UInt32 + let uint64: UInt64 + let float: Float + let double: Double + let bool: Bool + let date: Date + let data: Data } class DictionaryEncodingTests: XCTestCase { - func testEncodingDateFormats() throws { - let date = JustDate(date: Date(timeIntervalSinceReferenceDate: 123456.789)) - let encoder = DictionaryEncoder() - let encoded1 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded1["date"] as? TimeInterval, 123456.789) - - encoder.dateEncodingStrategy = .iso8601 - let encoded2 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded2["date"] as? String, "2001-01-02T10:17:36Z") - - encoder.dateEncodingStrategy = .millisecondsSince1970 - let encoded3 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded3["date"] as? Double, 978430656789.0) - - encoder.dateEncodingStrategy = .secondsSince1970 - let encoded4 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded4["date"] as? Double, 978430656.78900003) - - encoder.dateEncodingStrategy = .deferredToDate - let encoded5 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded5["date"] as? TimeInterval, 123456.789) - - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US") - formatter.setLocalizedDateFormatFromTemplate("MMMMd") - encoder.dateEncodingStrategy = .formatted(formatter) - let encoded6 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded6["date"] as? String, "January 2") - - var customEncoderCalled = false - encoder.dateEncodingStrategy = .custom({ (date, encoder) in - customEncoderCalled = true - try "some custom encoding".encode(to: encoder) - }) - let encoded7 = try encoder.encode(date) as [String:Any] - XCTAssertEqual(encoded7["date"] as? String, "some custom encoding") - XCTAssertEqual(customEncoderCalled, true) + var sut: DictionaryEncoder! + + override func setUp() { + sut = DictionaryEncoder() } - - func testEncodingDataFormats() throws { - let data = JustData(data: "blah".data(using: String.Encoding.utf8)!) - let encoder = DictionaryEncoder() - encoder.dataEncodingStrategy = .base64 - let encoded1 = try encoder.encode(data) as [String:Any] - XCTAssertEqual(encoded1["data"] as? String, "YmxhaA==") - - encoder.dataEncodingStrategy = .deferredToData - let encoded2 = try encoder.encode(data) as [String:Any] - XCTAssertEqual(encoded2["data"] as! [Int8], [98, 108, 97, 104]) - - var customEncoderCalled = false - encoder.dataEncodingStrategy = .custom({ (date, encoder) in - customEncoderCalled = true - try "some custom encoding".encode(to: encoder) - }) - let encoded3 = try encoder.encode(data) as [String:Any] - XCTAssertEqual(encoded3["data"] as? String, "some custom encoding") - XCTAssertEqual(customEncoderCalled, true) + + override func tearDown() { + sut = nil } - - func testEncodingAllTheTypes() throws { - let date = Date(timeIntervalSinceReferenceDate: 123456.789) - let test = AllTheTypes( - string: "blah", - int: -123456, int8: -123, int16: -12345, int32: -123456, int64: -123456789, - uint: 123456, uint8: 123, uint16: 12345, uint32: 123456, uint64: 123456789, - float: 123.456, double: 12345.6789, - bool: true, - date: date, - data: "test".data(using: String.Encoding.utf8)! - ) - let encoder = DictionaryEncoder() - let encoded = try encoder.encode(test) as [String:Any] - XCTAssertEqual(encoded["string"] as? String, "blah") + + func test_encoding_allTheTypes_shouldSucceed() throws { + // given + let test = AllTheTypes(string: "Hello World", int: -123456, int8: -123, int16: -12345, int32: -123456, int64: -123456789, uint: 123456, uint8: 123, uint16: 12345, uint32: 123456, uint64: 123456789, float: 123.456, double: 12345.6789, bool: true, date: Date(timeIntervalSinceReferenceDate: 123456.789), data: "test".data(using: String.Encoding.utf8)!) + + // when + let encoded = try sut.encode(test) as [String:Any] + + // then + XCTAssertEqual(encoded["string"] as? String, "Hello World") XCTAssertEqual(encoded["int"] as? Int, -123456) XCTAssertEqual(encoded["int8"] as? Int8, -123) XCTAssertEqual(encoded["int16"] as? Int16, -12345) @@ -131,64 +63,149 @@ class DictionaryEncodingTests: XCTestCase { XCTAssertEqual(encoded["float"] as? Float, 123.456) XCTAssertEqual(encoded["double"] as? Double, 12345.6789) XCTAssertEqual(encoded["bool"] as? Bool, true) - XCTAssertEqual(encoded["date"] as? Double, 123456.789) - XCTAssertEqual(encoded["data"] as? String, "dGVzdA==") + XCTAssertEqual(encoded["date"] as? Date, Date(timeIntervalSinceReferenceDate: 123456.789)) + XCTAssertEqual(encoded["data"] as? Data, "test".data(using: String.Encoding.utf8)!) + } + + func test_encoding_variousDateFormats_shouldSucceed() throws { + // given + struct JustDate: Codable { + let date: Date + } + + let test = JustDate(date: Date(timeIntervalSinceReferenceDate: 123456.789)) + + // when + let encoded1 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .deferredToDate + let encoded2 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .iso8601 + let encoded3 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .millisecondsSince1970 + let encoded4 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .secondsSince1970 + let encoded5 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .deferredToDate + let encoded6 = try sut.encode(test) as [String: Any] + + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US") + formatter.setLocalizedDateFormatFromTemplate("MMMMd") + sut.dateEncodingStrategy = .formatted(formatter) + let encoded7 = try sut.encode(test) as [String: Any] + + sut.dateEncodingStrategy = .custom { _, encoder in + try "some custom encoding".encode(to: encoder) + } + let encoded8 = try sut.encode(test) as [String: Any] + + // then + XCTAssertEqual(encoded1["date"] as? Date, Date(timeIntervalSinceReferenceDate: 123456.789)) + XCTAssertEqual(encoded2["date"] as? TimeInterval, 123456.789) + XCTAssertEqual(encoded3["date"] as? String, "2001-01-02T10:17:36Z") + XCTAssertEqual(encoded4["date"] as? Double, 978430656789.0) + XCTAssertEqual(encoded5["date"] as? Double, 978430656.78900003) + XCTAssertEqual(encoded6["date"] as? TimeInterval, 123456.789) + XCTAssertEqual(encoded7["date"] as? String, "January 2") + XCTAssertEqual(encoded8["date"] as? String, "some custom encoding") + } + + func test_encoding_variousDataFormats_shouldSucceed() throws { + // given + struct JustData: Codable { + let data: Data + } + + let test = JustData(data: "Foo".data(using: .utf8)!) + + // when + let encoded1 = try sut.encode(test) as [String: Any] + + sut.dataEncodingStrategy = .base64 + let encoded2 = try sut.encode(test) as [String: Any] + + sut.dataEncodingStrategy = .deferredToData + let encoded3 = try sut.encode(test) as [String: Any] + + sut.dataEncodingStrategy = .custom { _, encoder in + try "some custom encoding".encode(to: encoder) + } + let encoded4 = try sut.encode(test) as [String: Any] + + // then + XCTAssertEqual(encoded1["data"] as? Data, "Foo".data(using: .utf8)) + XCTAssertEqual(encoded2["data"] as? String, "Rm9v") + XCTAssertEqual(encoded3["data"] as? [UInt8], [70, 111, 111]) + XCTAssertEqual(encoded4["data"] as? String, "some custom encoding") } - - func testEncodingAsNSDictionary() throws { + + func test_encoding_asNSDictionary_shouldSucceed() throws { + // given let test = Person(name: "Sam", age: 48, pets:[Pet(name: "Morven"), Pet(name: "Rebus")]) - let encoder = DictionaryEncoder() - let encoded = try encoder.encode(test) as NSDictionary + + // when + let encoded = try sut.encode(test) as NSDictionary + + // then XCTAssertEqual(encoded["name"] as? String, "Sam") XCTAssertEqual(encoded["age"] as? Int, 48) - let pets = encoded["pets"] as! [NSDictionary] + let pets = try XCTUnwrap(encoded["pets"] as? [NSDictionary]) XCTAssertEqual(pets[0]["name"] as? String, "Morven") XCTAssertEqual(pets[1]["name"] as? String, "Rebus") } - func testEncodingAsSwiftDictionary() throws { - let test = Person(name: "Sam", age: 48, pets:[Pet(name: "Morven"), Pet(name: "Rebus")]) - let encoder = DictionaryEncoder() - let encoded = try encoder.encode(test) as [String:Any] + func test_encoding_asSwiftDictionary_shouldSucceed() throws { + // given + let test = Person(name: "Sam", age: 48, pets: [Pet(name: "Morven"), Pet(name: "Rebus")]) + + // when + let encoded = try sut.encode(test) as [String: Any] + + // then XCTAssertEqual(encoded["name"] as? String, "Sam") XCTAssertEqual(encoded["age"] as? Int, 48) - let pets = encoded["pets"] as! [NSDictionary] + let pets = try XCTUnwrap(encoded["pets"] as? [NSDictionary]) XCTAssertEqual(pets[0]["name"] as? String, "Morven") XCTAssertEqual(pets[1]["name"] as? String, "Rebus") } - func testEncodingOptionalValues() throws { - // the struct's optional values should not get written into the dictionary - // if they are nil - + // the struct's optional values should not get written into the dictionary + // if they are nil + func test_encoding_optionalValues_shouldSucceed() throws { + // given + struct Test: Codable { + let name: String + let label: String? + } + let test = Test(name: "Sam", label: nil) - let encoder = DictionaryEncoder() - let encoded = try encoder.encode(test) as NSDictionary + + // when + let encoded = try sut.encode(test) as NSDictionary + + // then XCTAssertEqual(encoded["name"] as? String, "Sam") - XCTAssertEqual(encoded.allKeys.count, 1) + XCTAssertEqual(encoded["label"] as? String, nil) } - func testEncodingURL() throws { + func test_encoding_url_shouldSucceed() throws { + // given struct Test : Encodable { let value : URL } - let string = "http://elegantchaos.com" - let test = Test(value: URL(string: string)!) - let encoder = DictionaryEncoder() - let encoded = try encoder.encode(test) as [String:Any] + let url = URL(string: "http://elegantchaos.com")! + let test = Test(value: url) - // currently URLs are encoded as strings - XCTAssertEqual(encoded["value"] as? String, string) - } + // when + let encoded = try sut.encode(test) as [String:Any] - static var allTests = [ - ("testEncodingDataFormats", testEncodingDataFormats), - ("testEncodingDateFormats", testEncodingDateFormats), - ("testEncodingAllTheTypes", testEncodingAllTheTypes), - ("testEncodingAsNSDictionary", testEncodingAsNSDictionary), - ("testEncodingAsSwiftDictionary", testEncodingAsSwiftDictionary), - ("testEncodingOptionalValues", testEncodingOptionalValues), - ("testEncodingURL", testEncodingURL), - ] + // then + XCTAssertEqual(encoded["value"] as? URL, url) + } }