diff --git a/JSONCodable.xcodeproj/project.pbxproj b/JSONCodable.xcodeproj/project.pbxproj index 8d4d68e..d55a368 100644 --- a/JSONCodable.xcodeproj/project.pbxproj +++ b/JSONCodable.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ BD885BBE1D17358E00CA767A /* EncodeNestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD885BBD1D17358E00CA767A /* EncodeNestingTests.swift */; }; BD885BC01D173A0700CA767A /* PropertyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD885BBF1D173A0700CA767A /* PropertyItem.swift */; }; BDD667CC1D1F3572003F94D7 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD667CB1D1F3572003F94D7 /* Messages.swift */; }; + C6FD31691DDDC31C00EF5141 /* DictionaryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6FD31681DDDC31C00EF5141 /* DictionaryTest.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -80,6 +81,7 @@ BD885BBD1D17358E00CA767A /* EncodeNestingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncodeNestingTests.swift; sourceTree = ""; }; BD885BBF1D173A0700CA767A /* PropertyItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyItem.swift; sourceTree = ""; }; BDD667CB1D1F3572003F94D7 /* Messages.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = ""; }; + C6FD31681DDDC31C00EF5141 /* DictionaryTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -138,6 +140,7 @@ 9E455BF91BCE185B00070A4F /* EnumTests.swift */, 9ECF00BF1BCE251B008D557C /* TransformerTests.swift */, A1B71C7D1D37E90B006DA33A /* MirrorTests.swift */, + C6FD31681DDDC31C00EF5141 /* DictionaryTest.swift */, A10DFC4B1DF71BF400B7D6D7 /* ClassInheritanceTests.swift */, ); name = Tests; @@ -292,6 +295,7 @@ buildActionMask = 2147483647; files = ( 52E8F44F1C9087D200F40F7F /* UtilityTests.swift in Sources */, + C6FD31691DDDC31C00EF5141 /* DictionaryTest.swift in Sources */, A1B71C801D37E982006DA33A /* ClassInheritance.swift in Sources */, 5211CD0A1CE2EBFB0097F255 /* NestItem.swift in Sources */, A1B71C7E1D37E90B006DA33A /* MirrorTests.swift in Sources */, diff --git a/JSONCodable.xcodeproj/xcshareddata/xcschemes/JSONCodable.xcscheme b/JSONCodable.xcodeproj/xcshareddata/xcschemes/JSONCodable.xcscheme index 603b4ee..d03a330 100644 --- a/JSONCodable.xcodeproj/xcshareddata/xcschemes/JSONCodable.xcscheme +++ b/JSONCodable.xcodeproj/xcshareddata/xcschemes/JSONCodable.xcscheme @@ -26,7 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> diff --git a/JSONCodable/JSONCodable.swift b/JSONCodable/JSONCodable.swift index 7aca03a..8a3f4a2 100644 --- a/JSONCodable/JSONCodable.swift +++ b/JSONCodable/JSONCodable.swift @@ -8,17 +8,32 @@ // convenience protocol -public protocol JSONCodable: JSONEncodable, JSONDecodable {} +public protocol JSONCodable: JSONEncodable, JSONCompatible {} // JSONCompatible - valid types in JSON public protocol JSONCompatible: JSONEncodable {} -extension String: JSONCompatible {} -extension Double: JSONCompatible {} -extension Float: JSONCompatible {} -extension Bool: JSONCompatible {} -extension Int: JSONCompatible {} +extension String: JSONDecodable, JSONCompatible { + public init(object: JSONObject) throws { + fatalError() + } +} +extension Double: JSONDecodable, JSONCompatible { + public init(object: JSONObject) throws { + fatalError() + } +} +extension Bool: JSONDecodable, JSONCompatible { + public init(object: JSONObject) throws { + fatalError() + } +} +extension Int: JSONDecodable, JSONCompatible { + public init(object: JSONObject) throws { + fatalError() + } +} extension JSONCompatible { public func toJSON() throws -> Any { diff --git a/JSONCodable/JSONDecodable.swift b/JSONCodable/JSONDecodable.swift index 7c45e56..8f5819e 100644 --- a/JSONCodable/JSONDecodable.swift +++ b/JSONCodable/JSONDecodable.swift @@ -49,7 +49,6 @@ public enum JSONDecodableError: Error, CustomStringConvertible { public protocol JSONDecodable { init(object: JSONObject) throws - init(object: [JSONObject]) throws } public extension JSONDecodable { @@ -87,7 +86,7 @@ public extension Array where Element: JSONDecodable { // JSONDecoder - provides utility methods for decoding -public class JSONDecoder { +public final class JSONDecoder { let object: JSONObject public init(object: JSONObject) { @@ -131,54 +130,22 @@ public class JSONDecoder { } return (result ?? object[key]).flatMap{$0 is NSNull ? nil : $0} } - - // JSONCompatible - public func decode(_ key: String) throws -> Compatible { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let compatible = value as? Compatible else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: Compatible.self) - } - return compatible - } - // JSONCompatible? - public func decode(_ key: String) throws -> Compatible? { - return (get(key) ?? object[key] as Any) as? Compatible - } // JSONDecodable public func decode(_ key: String) throws -> Decodable { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let object = value as? JSONObject else { - throw JSONDecodableError.dictionaryTypeExpectedError(key: key, elementType: type(of: value)) - } - return try Decodable(object: object) + return try gettingTransforms(key: key, transform: Decodable.init) } // JSONDecodable? public func decode(_ key: String) throws -> Decodable? { - guard let value = get(key) else { - return nil - } - guard let object = value as? JSONObject else { - throw JSONDecodableError.dictionaryTypeExpectedError(key: key, elementType: type(of: value)) - } - return try Decodable(object: object) + return try gettingTransformsOptional(key: key, transform: Decodable.init) } + // Enum public func decode(_ key: String) throws -> Enum { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let raw = value as? Enum.RawValue else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: Enum.RawValue.self) - } - guard let result = Enum(rawValue: raw) else { + guard let result = try decode(key) as Enum? else { throw JSONDecodableError.incompatibleTypeError(key: key, elementType: Enum.RawValue.self, expectedType: Enum.self) } return result @@ -186,184 +153,104 @@ public class JSONDecoder { // Enum? public func decode(_ key: String) throws -> Enum? { - guard let value = get(key) else { - return nil - } - guard let raw = value as? Enum.RawValue else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: Enum.RawValue.self) - } - guard let result = Enum(rawValue: raw) else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: Enum.RawValue.self, expectedType: Enum.self) - } - return result - } - - // [JSONCompatible] - public func decode(_ key: String, filter: Bool = false) throws -> [Element] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let array = value as? [Element] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [Element].self) - } - return array - } - - // [JSONCompatible]? - public func decode(_ key: String) throws -> [Element]? { - guard let value = get(key) else { - return nil - } - guard let array = value as? [Element] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [Element].self) - } - return array + return try gettingTransformsOptional(key: key, transform: Enum.init) } // [JSONDecodable] public func decode(_ key: String, filter: Bool = false) throws -> [Element] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let array = value as? [JSONObject] else { - throw JSONDecodableError.arrayTypeExpectedError(key: key, elementType: type(of: value)) - } - return try array.flatMap { - if filter { - return try? Element(object: $0) - } else { - return try Element(object: $0) + return try gettingTransforms(key: key, transform: { (preResult: [JSONObject]) in + return try preResult.flatMap { + if filter { + return try? Element(object: $0) + } else { + return try Element(object: $0) + } } - } + }) } // [JSONDecodable]? public func decode(_ key: String, filter: Bool = false) throws -> [Element]? { - guard let value = get(key) else { - return nil - } - guard let array = value as? [JSONObject] else { - throw JSONDecodableError.arrayTypeExpectedError(key: key, elementType: type(of: value)) - } - return try array.flatMap { - if filter { - return try? Element(object: $0) - } else { - return try Element(object: $0) + return try gettingTransformsOptional(key: key, transform: { (preResult: [JSONObject]) in + return try preResult.flatMap { + if filter { + return try? Element(object: $0) + } else { + return try Element(object: $0) + } } - } + }) } // [[JSONDecodable]] public func decode(_ key: String, filter: Bool = false) throws -> [[Element]] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let array = value as? [[JSONObject]] else { - throw JSONDecodableError.arrayTypeExpectedError(key: key, elementType: type(of: value)) - } - var res:[[Element]] = [] - - for x in array { - if filter { - let nested = x.flatMap { try? Element(object: $0)} - res.append(nested) - } else { - let nested = try x.flatMap { try Element(object: $0)} - res.append(nested) - } - } - return res - } - - // [[JSONCompatible]] - public func decode(_ key: String) throws -> [[Element]] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let array = value as? [[Element]] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [Element].self) - } - var res:[[Element]] = [] - - for x in array { - res.append(x) - } - return res + return try gettingTransforms(key: key, transform: { (preResult: [[JSONObject]]) in + return try preResult.map({ x in + if filter { + return x.flatMap { try? Element(object: $0)} + } else { + return try x.flatMap { try Element(object: $0)} + } + }) + }) } // [Enum] public func decode(_ key: String) throws -> [Enum] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let array = value as? [Enum.RawValue] else { - throw JSONDecodableError.arrayTypeExpectedError(key: key, elementType: type(of: value)) - } - return array.flatMap { Enum(rawValue: $0) } + return try gettingTransforms(key: key, transform: { (preResult: [Enum.RawValue]) in + return preResult.map { Enum(rawValue: $0)! } + }) } // [Enum]? public func decode(_ key: String) throws -> [Enum]? { - guard let value = get(key) else { - return nil - } - guard let array = value as? [Enum.RawValue] else { - throw JSONDecodableError.arrayTypeExpectedError(key: key, elementType: type(of: value)) - } - return array.flatMap { Enum(rawValue: $0) } + return try gettingTransformsOptional(key: key, transform: { (preResult: [Enum.RawValue]) in + return preResult.flatMap { Enum(rawValue: $0) } + }) } - // [String:JSONCompatible] - public func decode(_ key: String) throws -> [String: Value] { - guard let value = get(key) else { + + private func gettingTransforms(key: String, transform: (PreResult) throws -> T) throws -> T { + guard let value = try gettingTransformsOptional(key: key, transform: transform) else { throw JSONDecodableError.missingTypeError(key: key) } - guard let dictionary = value as? [String: Value] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [String: Value].self) - } - return dictionary + + return value } - // [String:JSONCompatible]? - public func decode(_ key: String) throws -> [String: Value]? { + private func gettingTransformsOptional(key: String, transform: (PreResult) throws -> T?) throws -> T? { guard let value = get(key) else { return nil } - guard let dictionary = value as? [String: Value] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [String: Value].self) + if let t = value as? T { + return t } - return dictionary + guard let preResult = value as? PreResult else { + throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: PreResult.self) + } + return try transform(preResult) } // [String:JSONDecodable] public func decode(_ key: String) throws -> [String: Element] { - guard let value = get(key) else { - throw JSONDecodableError.missingTypeError(key: key) - } - guard let dictionary = value as? [String: JSONObject] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [String: Element].self) - } - var decoded = [String: Element]() - try dictionary.forEach { - decoded[$0] = try Element(object: $1) - } - return decoded + return try gettingTransforms(key: key, transform: { (preResult: [String: JSONObject]) in + var decoded = [String: Element]() + try preResult.forEach { + decoded[$0] = try Element(object: $1) + } + return decoded + }) } // [String:JSONDecodable]? public func decode(_ key: String) throws -> [String: Element]? { - guard let value = get(key) else { - return nil - } - guard let dictionary = value as? [String: JSONObject] else { - throw JSONDecodableError.incompatibleTypeError(key: key, elementType: type(of: value), expectedType: [String: Element].self) - } - var decoded = [String: Element]() - try dictionary.forEach { - decoded[$0] = try Element(object: $1) - } - return decoded + return try gettingTransformsOptional(key: key, transform: { (preResult: [String: JSONObject]) in + var decoded = [String: Element]() + try preResult.forEach { + decoded[$0] = try Element(object: $1) + } + return decoded + }) } // JSONTransformable diff --git a/JSONCodable/JSONEncodable+Mirror.swift b/JSONCodable/JSONEncodable+Mirror.swift index 45d53eb..51a0033 100644 --- a/JSONCodable/JSONEncodable+Mirror.swift +++ b/JSONCodable/JSONEncodable+Mirror.swift @@ -13,11 +13,7 @@ public extension Mirror { - returns: array of Tuples containing the label and value for each property */ public func getAllProperties() -> [(label: String?, value: Any)] { - var children: [(label: String?, value: Any)] = [] - for element in self.children { - children.append(element) - } - + var children = Array(self.children) children.append(contentsOf: self.superclassMirror?.getAllProperties() ?? []) return children diff --git a/JSONCodableTests/ArrayTests.swift b/JSONCodableTests/ArrayTests.swift index ec1410d..b5393dc 100644 --- a/JSONCodableTests/ArrayTests.swift +++ b/JSONCodableTests/ArrayTests.swift @@ -7,11 +7,13 @@ // import XCTest +import JSONCodable class ArrayTests: XCTestCase { let mixedArrayJSON = [ [ + "idList": [1,2,3], "class": "propertyType", "rel": "propertyType", "properties": @@ -23,6 +25,7 @@ class ArrayTests: XCTestCase { ["name": "CompanyInc", "address": "1414 place st Los Angeles, CA"], [ + "idList": [1,2,3], "class": "propertyType", "rel": "propertyType", "properties": @@ -41,6 +44,20 @@ class ArrayTests: XCTestCase { ["name": "SoftwareInc", "address": "1313 place st Oakland, CA"] ] + + func testParseArray_WithInt() { + //Given + + let integers = ["array": [1, 2, 3]] + let parser = JSONDecoder(object: integers) + + //When + let parsed: Array? = try? parser.decode("array") + + //Then + XCTAssertNotNil(parsed) + XCTAssertEqual(parsed?.count, 3) + } func testMixedItemsInArray() { do { @@ -50,8 +67,8 @@ class ArrayTests: XCTestCase { XCTFail() return } - XCTAssert(companiesEncoded.count == 2, "encoding invalid") - XCTAssert(companiesJSON.count == 2, "companies mapping invalid") + XCTAssertEqual(companiesEncoded.count, 2, "encoding invalid") + XCTAssertEqual(companiesJSON.count, 2, "companies mapping invalid") XCTAssert(companiesEncoded[0] == companiesJSON[0], "companies values incorrect") XCTAssert(companiesEncoded[1] == companiesJSON[1], "companies values incorrect") print(companies) @@ -70,16 +87,141 @@ class ArrayTests: XCTestCase { } } - func testCompanyProperties() { - let companyPropertiesJSON = ["companies_properties" : mixedArrayJSON] +// func testCompanyProperties() { +// let companyPropertiesJSON = ["companies_properties" : mixedArrayJSON] +// do { +// let companiesAndProperties = try PropertyCompany(object: companyPropertiesJSON) +// print(companiesAndProperties) +// } catch { +// print(error) +// XCTFail() +// } +// +// } + + + func parse(json: Dictionary, expectedResult: Array, file: StaticString = #file, line: UInt = #line) where T: Equatable { + //Given + let decoder = JSONDecoder(object: json) + + //When do { - let companiesAndProperties = try PropertyCompany(object: companyPropertiesJSON) - print(companiesAndProperties) + let result: [T] = try decoder.decode("values") + XCTAssertEqual(result.count, 3) + XCTAssertEqual(result[0], expectedResult[0], file: file, line: line) + XCTAssertEqual(result[1], expectedResult[1], file: file, line: line) + XCTAssertEqual(result[2], expectedResult[2], file: file, line: line) + let optionalResult: [T]? = try decoder.decode("values") + XCTAssertEqual(result.count, 3) + XCTAssertEqual(result[0], optionalResult?[0], file: file, line: line) + XCTAssertEqual(result[1], optionalResult?[1], file: file, line: line) + XCTAssertEqual(result[2], optionalResult?[2], file: file, line: line) + } catch let err as JSONDecodableError { + XCTFail(err.description, file: file, line: line) } catch { - print(error) + XCTFail("Failed with unspecified error") + } + } + + func parse(expectedResult: Array, file: StaticString = #file, line: UInt = #line) where T: Equatable { + //Given + let json = ["values": expectedResult] + + //When + parse(json: json, expectedResult: expectedResult, file: file, line: line) + } + + func testParse_withInt() { + //Given + let values = [0, 1, 2] + + //When + parse(expectedResult: values) + } + + func testParse_withInt_empty() { + //Given + let json = ["values": []] + let decoder = JSONDecoder(object: json) + + //When + do { + let result: [Int] = try decoder.decode("values") + XCTAssertEqual(result.count, 0) + + } catch let err { XCTFail() } - + } + + func testParse_withString() { + //Given + let values = ["0", "1", "2"] + //When + parse(expectedResult: values) + } + + func testParse_withDouble() { + //Given + let values = [0.0, 0.1, 0.2] + + //When + parse(expectedResult: values) + } + + func testParse_withBool() { + //Given + let values = [true, false, true] + + //When + parse(expectedResult: values) + } + + func testParse_withEnum() { + //Given + let result = ["Red", "Blue", "Red"] + let expectedResult = [FruitColor.Red, FruitColor.Blue, FruitColor.Red] + + let json = ["values": result] + let decoder = JSONDecoder(object: json) + + //When + do { + let result: [FruitColor] = try decoder.decode("values") + XCTAssertEqual(result.count, 3) + XCTAssertEqual(result[0], expectedResult[0]) + XCTAssertEqual(result[1], expectedResult[1]) + XCTAssertEqual(result[2], expectedResult[2]) + let optionalResult: [FruitColor]? = try decoder.decode("values") + XCTAssertEqual(result.count, 3) + XCTAssertEqual(result[0], optionalResult?[0]) + XCTAssertEqual(result[1], optionalResult?[1]) + XCTAssertEqual(result[2], optionalResult?[2]) + } catch let err as JSONDecodableError { + XCTFail(err.description) + } catch { + XCTFail("Failed with unspecified error") + } + } + + func testParse_withObject() { + let json = ["values": [["name": "1", "address": "2"], ["name": "2"]]] + + let decoder = JSONDecoder(object: json) + do { + let result: [Company] = try decoder.decode("values") + XCTAssertEqual(result[0], Company(name: "1", address: "2")) + XCTAssertEqual(result[1], Company(name: "2", address: nil)) + + let resultOptional: [Company]? = try decoder.decode("values") + XCTAssertEqual(resultOptional?[0], Company(name: "1", address: "2")) + XCTAssertEqual(resultOptional?[1], Company(name: "2", address: nil)) + + } catch let err as JSONDecodableError { + XCTFail(err.description) + } catch { + XCTFail("Failed with unspecified error") + } } } diff --git a/JSONCodableTests/ClassInheritanceTests.swift b/JSONCodableTests/ClassInheritanceTests.swift index a89c916..6acaf82 100644 --- a/JSONCodableTests/ClassInheritanceTests.swift +++ b/JSONCodableTests/ClassInheritanceTests.swift @@ -18,8 +18,10 @@ class ClassInheritanceTests: XCTestCase { do { //Act - let json = try child.toJSON() as? JSONObject - let newChild = try Child(object: json!) + guard let json = try child.toJSON() as? JSONObject else { + return XCTFail("json should not be nil") + } + let newChild = try Child(object: json) // Assert XCTAssertEqual(child.parentProperty1, newChild.parentProperty1) diff --git a/JSONCodableTests/DictionaryTest.swift b/JSONCodableTests/DictionaryTest.swift new file mode 100644 index 0000000..b431441 --- /dev/null +++ b/JSONCodableTests/DictionaryTest.swift @@ -0,0 +1,174 @@ +// +// Copyright (C) 2016 Lukas Schmidt. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// DictionaryTest.swift +// JSONCodable +// +// Created by Lukas Schmidt on 17.11.16. +// + +import XCTest +@testable import JSONCodable + +struct Value { + let id: Int +} + +extension Value: JSONDecodable { + init(object: JSONObject) throws { + let decoder = JSONDecoder(object: object) + id = try decoder.decode("id") + } +} + +class DictionaryTest: XCTestCase { + + func testParse_withInt() { + //Given + let json = ["dict": ["id": 1]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Int] = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result["id"], 1) + } + + func testParse_withString() { + //Given + let json = ["dict": ["id": "1"]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: String] = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result["id"], "1") + } + + func testParse_withDouble() { + //Given + let json = ["dict": ["id": 1.00]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Double] = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result["id"], 1.00) + } + + func testParse_withBool() { + //Given + let json = ["dict": ["id": true]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Bool] = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result["id"], true) + } + + func testParse_withBool_optional() { + //Given + let json = ["dict": ["id": true]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Bool]? = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result?["id"], true) + } + + func testParse_withInt_optional() { + //Given + let json = ["dict": ["id": 1]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Int]? = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result?["id"], 1) + } + + func testParse_withString_optional() { + //Given + let json = ["dict": ["id": "1"]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: String]? = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result?["id"], "1") + } + + func testParse_withDouble_optional() { + //Given + let json = ["dict": ["id": 1.00]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Double]? = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result?["id"], 1.00) + } + + func testParse_object() { + //Given + let json = ["dict": ["dict": ["id": 1]]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Value] = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result["dict"]?.id, 1) + } + + func testParse_object_optional() { + //Given + let json = ["dict": ["dict": ["id": 1]]] + let decoder = JSONDecoder(object: json) + + //When + let result: [String: Value]? = try! decoder.decode("dict") + + //Then + XCTAssertNotNil(result) + XCTAssertEqual(result?["dict"]?.id, 1) + } +} diff --git a/JSONCodableTests/EnumTests.swift b/JSONCodableTests/EnumTests.swift index 5a1c9d7..c5d9c18 100644 --- a/JSONCodableTests/EnumTests.swift +++ b/JSONCodableTests/EnumTests.swift @@ -7,6 +7,7 @@ // import XCTest +import JSONCodable class EnumTests: XCTestCase { @@ -16,6 +17,18 @@ class EnumTests: XCTestCase { let encodedValue2: [String: Any] = ["name": "Seaweed Pasta", "cuisines": ["Italian", "Japanese"]] let decodedValue2 = Food(name: "Seaweed Pasta", cuisines: [.Italian, .Japanese]) + func testDecodingEnum_withValidValues() { + //Given + let values = ["fruitColor": "Red"] + let decoder = JSONDecoder(object: values) + + //When + let red: FruitColor = try! decoder.decode("fruitColor") + + //Then + XCTAssertEqual(red, .Red) + } + func testDecodingEnum() { guard let fruit = try? Fruit(object: encodedValue) else { XCTFail() diff --git a/JSONCodableTests/HelperTests.swift b/JSONCodableTests/HelperTests.swift index 5ccffce..6f2a548 100644 --- a/JSONCodableTests/HelperTests.swift +++ b/JSONCodableTests/HelperTests.swift @@ -14,36 +14,36 @@ struct NotEncodable { class HelperTests: XCTestCase { - func testArrayElementsAreEncodable() { - let intArray:[Int] = [1,2,3] - XCTAssert(intArray.elementsAreJSONEncodable(), "Array of type [Int] should be encodable") - - let encodableArray:[JSONEncodable] = [1,2,3] - XCTAssert(encodableArray.elementsAreJSONEncodable(), "Array of type [JSONEncodable] should be encodable") - - let notEncodableArray:[NotEncodable] = [NotEncodable()] - XCTAssert(!notEncodableArray.elementsAreJSONEncodable(), "Array of type [NotEncodable] should not be encodable") - - let _ = try? JSONEncoder.create({ (encoder) -> Void in - try encoder.encode(intArray, key: "intArray") - try encoder.encode(encodableArray, key: "encodableArray") - }) - } - - func testDictionaryIsEncodable() { - let intDict:[String:Int] = ["a":1,"b":2,"c":3] - XCTAssert(intDict.valuesAreJSONEncodable(), "Dictionary of type [String:Int] should be encodable") - - let encodableDict:[String:JSONEncodable] = ["a":1,"b":2,"c":3] - XCTAssert(encodableDict.valuesAreJSONEncodable(), "Dictionary of type [String:JSONEncodable] should be encodable") - - let notEncodableDict:[String:NotEncodable] = ["a":NotEncodable()] - XCTAssert(!notEncodableDict.valuesAreJSONEncodable(), "Dictionary of type [String:NotEncodable] should not be encodable") - - let _ = try? JSONEncoder.create({ (encoder) -> Void in - try encoder.encode(intDict, key: "intArray") - try encoder.encode(encodableDict, key: "encodableArray") - }) - } +// func testArrayElementsAreEncodable() { +// let intArray:[Int] = [1,2,3] +// XCTAssert(intArray.elementsAreJSONEncodable(), "Array of type [Int] should be encodable") +// +// let encodableArray:[JSONDecodable] = [1,2,3] +// XCTAssert(encodableArray.elementsAreJSONEncodable(), "Array of type [JSONEncodable] should be encodable") +// +// let notEncodableArray:[NotEncodable] = [NotEncodable()] +// XCTAssert(!notEncodableArray.elementsAreJSONEncodable(), "Array of type [NotEncodable] should not be encodable") +// +// let _ = try? JSONEncoder.create({ (encoder) -> Void in +// try encoder.encode(intArray, key: "intArray") +// try encoder.encode(encodableArray, key: "encodableArray") +// }) +// } +// +// func testDictionaryIsEncodable() { +// let intDict:[String:Int] = ["a":1,"b":2,"c":3] +// XCTAssert(intDict.valuesAreJSONEncodable(), "Dictionary of type [String:Int] should be encodable") +// +// let encodableDict:[String:JSONEncodable] = ["a":1,"b":2,"c":3] +// XCTAssert(encodableDict.valuesAreJSONEncodable(), "Dictionary of type [String:JSONEncodable] should be encodable") +// +// let notEncodableDict:[String:NotEncodable] = ["a":NotEncodable()] +// XCTAssert(!notEncodableDict.valuesAreJSONEncodable(), "Dictionary of type [String:NotEncodable] should not be encodable") +// +// let _ = try? JSONEncoder.create({ (encoder) -> Void in +// try encoder.encode(intDict, key: "intArray") +// try encoder.encode(encodableDict, key: "encodableArray") +// }) +// } } diff --git a/JSONCodableTests/PropertyCompany.swift b/JSONCodableTests/PropertyCompany.swift index 3ca1c1d..bcab1ad 100644 --- a/JSONCodableTests/PropertyCompany.swift +++ b/JSONCodableTests/PropertyCompany.swift @@ -11,6 +11,7 @@ import JSONCodable struct PropertyCompany { let properties: [PropertyItem] let companies: [Company] + let idList: [Int] } extension PropertyCompany: JSONEncodable {} @@ -20,5 +21,6 @@ extension PropertyCompany: JSONDecodable { let decoder = JSONDecoder(object: object) properties = try decoder.decode("companies_properties", filter: true) companies = try decoder.decode("companies_properties", filter: true) + idList = try decoder.decode("idList") } } diff --git a/JSONCodableTests/RegularTests.swift b/JSONCodableTests/RegularTests.swift index 4de05fd..e5c72b6 100644 --- a/JSONCodableTests/RegularTests.swift +++ b/JSONCodableTests/RegularTests.swift @@ -7,7 +7,7 @@ // import XCTest - +import JSONCodable class RegularTests: XCTestCase { @@ -51,11 +51,11 @@ class RegularTests: XCTestCase { "address": "1 Infinite Loop, Cupertino, CA" ], "friends": [ - ["id": 27, "full_name": "Bob Jefferson", "friends" : [], ], - ["id": 29, "full_name": "Jen Jackson", "friends" : [], - ] + ["id": 27, "full_name": "Bob Jefferson", "friends": []], + ["id": 29, "full_name": "Jen Jackson", "friends": []] ], - "friendsLookup": ["Bob Jefferson": ["id": 27, "friends" : [], "full_name": "Bob Jefferson"]] + "friendsLookup": ["Bob Jefferson": ["id": 27, "full_name": "Bob Jefferson", "friends": []]] + ] let decodedValue = User( id: 24, @@ -72,12 +72,15 @@ class RegularTests: XCTestCase { func testArrayOfUsers() { let userArray = [encodedValue, encodedValue] - guard let users = try? [User](JSONArray: userArray) else { + do { + let users = try [User](JSONArray: userArray) + XCTAssertEqual(users[0], decodedValue) + XCTAssertEqual(users[1], decodedValue) + } catch let error as JSONDecodableError { + XCTFail("Failed with error: \(error.description)") + } catch { XCTFail() - return } - XCTAssertEqual(users[0], decodedValue) - XCTAssertEqual(users[1], decodedValue) } func testDecodeNestedCodableArray() { @@ -85,7 +88,7 @@ class RegularTests: XCTestCase { XCTFail() return } - print("nested=",nested) + print("nested=", nested) let places = nested.places ?? [[]] let areas = nested.areas let business = nested.business