From 46be066edfd24b1b8352c7471646975c54b97cfa Mon Sep 17 00:00:00 2001 From: Johannes Lund Date: Sun, 19 Jul 2015 12:26:28 +0200 Subject: [PATCH] Add missing overloads and tests --- Decodable.xcodeproj/project.pbxproj | 12 +- Decodable/Decodable.swift | 6 + Decodable/Operators.swift | 20 ++- Decodable/PlsFixSwift.swift | 34 ++++- DecodableTests/ArrayTests.swift | 135 +++++++++++++++++++ DecodableTests/DecodableOperatorsTests.swift | 101 +------------- 6 files changed, 196 insertions(+), 112 deletions(-) create mode 100644 DecodableTests/ArrayTests.swift diff --git a/Decodable.xcodeproj/project.pbxproj b/Decodable.xcodeproj/project.pbxproj index 00fb5f3..21f4760 100644 --- a/Decodable.xcodeproj/project.pbxproj +++ b/Decodable.xcodeproj/project.pbxproj @@ -10,12 +10,14 @@ 17FB81011B530FED0012F106 /* Decodable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17FB80F71B530FED0012F106 /* Decodable.framework */; }; 17FB810E1B5311840012F106 /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FE7B57C1B4CA01400837609 /* Decodable.swift */; }; 17FB810F1B5311870012F106 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F956D1E1B4D6FF700243072 /* Operators.swift */; }; + 8F4B52651B5BAA5700FDCBA7 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F4B52641B5BAA5700FDCBA7 /* ArrayTests.swift */; }; + 8F4B52661B5BAA5700FDCBA7 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F4B52641B5BAA5700FDCBA7 /* ArrayTests.swift */; }; 8F87BCBB1B580CE200E53A8C /* ErrorPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCBA1B580CE200E53A8C /* ErrorPathTests.swift */; }; 8F87BCBC1B580CE200E53A8C /* ErrorPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCBA1B580CE200E53A8C /* ErrorPathTests.swift */; }; - 8F87BCC41B592F0E00E53A8C /* DecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */; }; - 8F87BCC51B592F0E00E53A8C /* DecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */; }; 8F87BCC11B58643200E53A8C /* PlsFixSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC01B58643200E53A8C /* PlsFixSwift.swift */; }; 8F87BCC21B58643200E53A8C /* PlsFixSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC01B58643200E53A8C /* PlsFixSwift.swift */; }; + 8F87BCC41B592F0E00E53A8C /* DecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */; }; + 8F87BCC51B592F0E00E53A8C /* DecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */; }; 8F956D1F1B4D6FF700243072 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F956D1E1B4D6FF700243072 /* Operators.swift */; }; 8FE7B5661B4C9FB900837609 /* Decodable.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FE7B5651B4C9FB900837609 /* Decodable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8FE7B56D1B4C9FB900837609 /* Decodable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8FE7B5621B4C9FB900837609 /* Decodable.framework */; }; @@ -58,9 +60,10 @@ /* Begin PBXFileReference section */ 17FB80F71B530FED0012F106 /* Decodable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Decodable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 17FB81001B530FED0012F106 /* DecodableTests-Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DecodableTests-Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8F4B52641B5BAA5700FDCBA7 /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; 8F87BCBA1B580CE200E53A8C /* ErrorPathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorPathTests.swift; sourceTree = ""; }; - 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodingError.swift; sourceTree = ""; }; 8F87BCC01B58643200E53A8C /* PlsFixSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlsFixSwift.swift; sourceTree = ""; }; + 8F87BCC31B592F0E00E53A8C /* DecodingError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodingError.swift; sourceTree = ""; }; 8F956D1E1B4D6FF700243072 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; 8FE7B5621B4C9FB900837609 /* Decodable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Decodable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8FE7B5651B4C9FB900837609 /* Decodable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Decodable.h; sourceTree = ""; }; @@ -152,6 +155,7 @@ 8FE7B5711B4C9FB900837609 /* DecodableTests.swift */, FF00609D1B5454F400D8CB77 /* DecodableExtensionTests.swift */, FF0060AF1B546FB100D8CB77 /* DecodableOperatorsTests.swift */, + 8F4B52641B5BAA5700FDCBA7 /* ArrayTests.swift */, 8F87BCBA1B580CE200E53A8C /* ErrorPathTests.swift */, FFE77E1E1B5391AD00E52F28 /* Repository.swift */, 8FE7B5731B4C9FB900837609 /* Info.plist */, @@ -365,6 +369,7 @@ 8F87BCBC1B580CE200E53A8C /* ErrorPathTests.swift in Sources */, FF00609F1B5454F400D8CB77 /* DecodableExtensionTests.swift in Sources */, FF0060B11B546FB100D8CB77 /* DecodableOperatorsTests.swift in Sources */, + 8F4B52661B5BAA5700FDCBA7 /* ArrayTests.swift in Sources */, FFE77E211B5396FB00E52F28 /* Repository.swift in Sources */, FF0060981B5453C600D8CB77 /* DecodableTests.swift in Sources */, ); @@ -388,6 +393,7 @@ 8F87BCBB1B580CE200E53A8C /* ErrorPathTests.swift in Sources */, FF00609E1B5454F400D8CB77 /* DecodableExtensionTests.swift in Sources */, FF0060B01B546FB100D8CB77 /* DecodableOperatorsTests.swift in Sources */, + 8F4B52651B5BAA5700FDCBA7 /* ArrayTests.swift in Sources */, 8FE7B5721B4C9FB900837609 /* DecodableTests.swift in Sources */, FFE77E221B5396FC00E52F28 /* Repository.swift in Sources */, ); diff --git a/Decodable/Decodable.swift b/Decodable/Decodable.swift index 41f1946..2f9341c 100644 --- a/Decodable/Decodable.swift +++ b/Decodable/Decodable.swift @@ -12,6 +12,12 @@ public protocol Decodable { static func decode(json: AnyObject) throws -> Self } +public protocol MetaDecodable { + typealias MetaType + var objects: MetaType {get} + static func decode(json: AnyObject, type: Decodable.Type) throws -> MetaType +} + public protocol Castable: Decodable {} extension Castable { public static func decode(j: AnyObject) throws -> Self { diff --git a/Decodable/Operators.swift b/Decodable/Operators.swift index 8dac96a..f809f5e 100644 --- a/Decodable/Operators.swift +++ b/Decodable/Operators.swift @@ -33,6 +33,15 @@ private func catchErrorAndAppendPath(path: String, block: ((AnyObject) throws } } +private func catchErrorAndSetRootObject(object: AnyObject, block: (Void throws -> T)) throws -> T { + do { + return try block() + } catch var error as DecodingError { + error.info.rootObject = object + throw error + } +} + // MARK: Operators // Middle @@ -66,7 +75,9 @@ public func => (lhs: AnyObject, rhs: ((AnyObject) throws -> T)) throws -> T public func => (lhs: AnyObject, rhs: String) throws -> T { - return try T.decode(parse(lhs, key: rhs)) + return try catchErrorAndSetRootObject(lhs) { + try T.decode(parse(lhs, key: rhs)) + } } // MARK: Optionals @@ -80,12 +91,10 @@ public func => (lhs: AnyObject, rhs: String) -> T? } } -// MARK: Optional Arrays - -public func => (lhs: AnyObject, rhs: String) -> [T]? +public func => (lhs: AnyObject, rhs: ((AnyObject) throws -> T)) throws -> T? { do { - return try lhs => rhs as [T] + return try rhs(lhs) } catch { return nil } @@ -103,7 +112,6 @@ public func => (lhs: AnyObject, rhs: ((AnyObject) throws -> [String: AnyObject]) return try JSONDictionary.decode(rhs(lhs)) } - private func printArrayError(error: DecodingError) { print("Error caught in nil-filtering Array Decoder (=>?): \(error)") } diff --git a/Decodable/PlsFixSwift.swift b/Decodable/PlsFixSwift.swift index a1cc2b1..5ca6f11 100644 --- a/Decodable/PlsFixSwift.swift +++ b/Decodable/PlsFixSwift.swift @@ -52,14 +52,42 @@ public struct NilFilteringArray: Decodable { } } - - public func => (lhs: AnyObject, rhs: String) throws -> [T] { return try ((lhs => rhs) as DecodableArray).value } + public func =>? (lhs: AnyObject, rhs: String) throws -> [T] { return try ((lhs => rhs) as NilFilteringArray).value -} \ No newline at end of file +} + +public func => (lhs: AnyObject, rhs: ((AnyObject) throws -> DecodableArray)) throws -> [T] +{ + return try (rhs(lhs) as DecodableArray).value +} + +public func =>? (lhs: AnyObject, rhs: ((AnyObject) throws -> NilFilteringArray)) throws -> [T] +{ + return try (rhs(lhs) as NilFilteringArray).value +} + +// Optionals + +public func => (lhs: AnyObject, rhs: String) -> [T]? { + do { + return try ((lhs => rhs) as DecodableArray).value + } catch { + return nil + } +} + +public func => (lhs: AnyObject, rhs: ((AnyObject) throws -> DecodableArray)) -> [T]? +{ + do { + return try (rhs(lhs) as DecodableArray).value + } catch { + return nil + } +} diff --git a/DecodableTests/ArrayTests.swift b/DecodableTests/ArrayTests.swift new file mode 100644 index 0000000..80d3b30 --- /dev/null +++ b/DecodableTests/ArrayTests.swift @@ -0,0 +1,135 @@ +// +// ArrayTests.swift +// Decodable +// +// Created by Johannes Lund on 2015-07-19. +// Copyright © 2015 anviking. All rights reserved. +// + +import XCTest +@testable import Decodable + +class DecodableArrayTests: XCTestCase { + + func testDecodeAnyDecodableArraySuccess() { + // given + let key = "key" + let value: NSArray = ["value1", "value2", "value3"] + let dictionary: NSDictionary = [key: value] + // when + let result = try! dictionary => key as Array + // then + XCTAssertEqual(result, value) + } + + func testDecodeNestedDecodableArraySuccess() { + // given + let key = "key" + let value: NSArray = ["value1", "value2", "value3"] + let dictionary: NSDictionary = [key: [key: value]] + // when + let result = try! dictionary => key => key as Array + // then + XCTAssertEqual(result, value) + } + + func testDecodeAnyDecodableOptionalArraySuccess() { + // given + let key = "key" + let value = ["value"] + let dictionary: NSDictionary = [key: value] + // when + let string = dictionary => key as [String]? + // then + XCTAssertEqual(string!, value) + } + + func testDecodeAnyDecodableNestedOptionalArraySuccess() { + // given + let key = "key" + let value = ["value"] + let dictionary: NSDictionary = [key: [key: value]] + // when + let string = dictionary => key => key as [String]? + // then + XCTAssertEqual(string!, value) + } + + func testDecodeAnyDecodableOptionalArrayNilSuccess() { + // given + let key = "key" + let dictionary: NSDictionary = [key: NSNull()] + // when + let string = dictionary => key as [String]? + // then + XCTAssertNil(string) + } + + func testDecodeAnyDecodableOptionalArrayMissingKeySuccess() { + // given + let key = "key" + let dictionary = NSDictionary() + // when + let string = dictionary => key as [String]? + // then + XCTAssertNil(string) + } + + + // MARK: =>? + + func testDecodeSafeArraySuccess() { + // given + let key = "key" + let value = ["A", "B", "C"] + let dictionary: NSDictionary = [key: value] + // when + let string = try! dictionary =>? key as [String] + // then + XCTAssertEqual(string, value) + } + + func testDecodeSafeArrayCatchTypeExceptionMismatch() { + // given + let key = "key" + let value = ["A", 2, "B"] + let dictionary: NSDictionary = [key: value] + // when + let string = try! dictionary =>? key as [String] + // then + XCTAssertEqual(string, ["A", "B"]) + } + + func testDecodeSafeArrayCatchTypeMismatchExceptionInObjects() { + // given + let key = "key" + let value = [["id": "007", "login": "mradams"], ["id": 1, "login": "jenglish"]] + let dictionary: NSDictionary = [key: value] + // when + let array = try! dictionary =>? key as [Owner] + // then + XCTAssertEqual(array, [Owner(id: 1, login: "jenglish")]) + } + + func testDecodeSafeArrayCatchJSONNotObjectException() { + // given + let key = "key" + let value = [["id": 7, "login": "mradams"], 2] + let dictionary: NSDictionary = [key: value] + // when + let array = try! dictionary =>? key as [Owner] + // then + XCTAssertEqual(array, [Owner(id: 7, login: "mradams")]) + } + + func testDecodeSafeArrayCatchMissingKeyException() { + // given + let key = "key" + let value = [["login": "mradams"], ["id": 1, "login": "jenglish"]] + let dictionary: NSDictionary = [key: value] + // when + let array = try! dictionary =>? key as [Owner] + // then + XCTAssertEqual(array, [Owner(id: 1, login: "jenglish")]) + } +} \ No newline at end of file diff --git a/DecodableTests/DecodableOperatorsTests.swift b/DecodableTests/DecodableOperatorsTests.swift index 7bf0f7f..1706396 100644 --- a/DecodableTests/DecodableOperatorsTests.swift +++ b/DecodableTests/DecodableOperatorsTests.swift @@ -51,7 +51,7 @@ class DecodableOperatorsTests: XCTestCase { // given let key = "key" let value: NSDictionary = ["aKey" : "value"] - let dictionary: NSDictionary = [key: [key: value]] + let dictionary: [String: AnyObject] = [key: [key: value]] // when let result: [String: AnyObject]? = dictionary => key => key // then @@ -91,48 +91,6 @@ class DecodableOperatorsTests: XCTestCase { XCTAssertNil(string) } - func testDecodeAnyDecodableArraySuccess() { - // given - let key = "key" - let value: NSArray = ["value1", "value2", "value3"] - let dictionary: NSDictionary = [key: value] - // when - let result = try! dictionary => key as Array - // then - XCTAssertEqual(result, value) - } - - func testDecodeAnyDecodableOptionalArraySuccess() { - // given - let key = "key" - let value = ["value"] - let dictionary: NSDictionary = [key: value] - // when - let string = dictionary => key as [String]? - // then - XCTAssertEqual(string!, value) - } - - func testDecodeAnyDecodableOptionalArrayNilSuccess() { - // given - let key = "key" - let dictionary: NSDictionary = [key: NSNull()] - // when - let string = dictionary => key as [String]? - // then - XCTAssertNil(string) - } - - func testDecodeAnyDecodableOptionalArrayMissingKeySuccess() { - // given - let key = "key" - let dictionary = NSDictionary() - // when - let string = dictionary => key as [String]? - // then - XCTAssertNil(string) - } - // MARK: => Errors @@ -242,61 +200,4 @@ class DecodableOperatorsTests: XCTestCase { XCTFail("should not throw this exception") } } - - // MARK: =>? - - func testDecodeSafeArraySuccess() { - // given - let key = "key" - let value = ["A", "B", "C"] - let dictionary: NSDictionary = [key: value] - // when - let string = try! dictionary =>? key as [String] - // then - XCTAssertEqual(string, value) - } - - func testDecodeSafeArrayCatchTypeExceptionMismatch() { - // given - let key = "key" - let value = ["A", 2, "B"] - let dictionary: NSDictionary = [key: value] - // when - let string = try! dictionary =>? key as [String] - // then - XCTAssertEqual(string, ["A", "B"]) - } - - func testDecodeSafeArrayCatchTypeMismatchExceptionInObjects() { - // given - let key = "key" - let value = [["id": "007", "login": "mradams"], ["id": 1, "login": "jenglish"]] - let dictionary: NSDictionary = [key: value] - // when - let array = try! dictionary =>? key as [Owner] - // then - XCTAssertEqual(array, [Owner(id: 1, login: "jenglish")]) - } - - func testDecodeSafeArrayCatchJSONNotObjectException() { - // given - let key = "key" - let value = [["id": 7, "login": "mradams"], 2] - let dictionary: NSDictionary = [key: value] - // when - let array = try! dictionary =>? key as [Owner] - // then - XCTAssertEqual(array, [Owner(id: 7, login: "mradams")]) - } - - func testDecodeSafeArrayCatchMissingKeyException() { - // given - let key = "key" - let value = [["login": "mradams"], ["id": 1, "login": "jenglish"]] - let dictionary: NSDictionary = [key: value] - // when - let array = try! dictionary =>? key as [Owner] - // then - XCTAssertEqual(array, [Owner(id: 1, login: "jenglish")]) - } }