Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

Commit

Permalink
Fix crash related to an invalid nested json (by keypath)
Browse files Browse the repository at this point in the history
  • Loading branch information
Otbivnoe committed Mar 9, 2019
1 parent 733cec1 commit 60e2c68
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 7 deletions.
24 changes: 24 additions & 0 deletions CodableAlamofire.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
8472D2F91EED3C5F00E81232 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8472D2F71EED3C5400E81232 /* Alamofire.framework */; };
8472D2FA1EED3C6300E81232 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8472D2F31EED3C5400E81232 /* Alamofire.framework */; };
8472D2FB1EED3C6A00E81232 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8472D2EF1EED3C5400E81232 /* Alamofire.framework */; };
84A389C52233CCC200A0A66A /* keypathArray.json in Resources */ = {isa = PBXBuildFile; fileRef = 84A389BA2233CCC200A0A66A /* keypathArray.json */; };
84A389C62233CCC200A0A66A /* keypathObject.json in Resources */ = {isa = PBXBuildFile; fileRef = 84A389BB2233CCC200A0A66A /* keypathObject.json */; };
84A389C72233CCC200A0A66A /* object.json in Resources */ = {isa = PBXBuildFile; fileRef = 84A389BC2233CCC200A0A66A /* object.json */; };
84A389CB2233D9F500A0A66A /* emptyKeypath.json in Resources */ = {isa = PBXBuildFile; fileRef = 84A389CA2233D9F500A0A66A /* emptyKeypath.json */; };
84A8C8501EED2F2700AB31BE /* CodableAlamofire.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A8C84D1EED2F0C00AB31BE /* CodableAlamofire.h */; settings = {ATTRIBUTES = (Public, ); }; };
84A8C8511EED2F2700AB31BE /* CodableAlamofire.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A8C84D1EED2F0C00AB31BE /* CodableAlamofire.h */; settings = {ATTRIBUTES = (Public, ); }; };
84A8C8521EED2F2800AB31BE /* CodableAlamofire.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A8C84D1EED2F0C00AB31BE /* CodableAlamofire.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -119,6 +123,10 @@
8472D2BB1EED3B8C00E81232 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = "Carthage/Checkouts/Alamofire/build/Debug-appletvos/Alamofire.framework"; sourceTree = "<group>"; };
8472D2DE1EED3C4E00E81232 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = "Carthage/Checkouts/Alamofire/build/Debug-appletvos/Alamofire.framework"; sourceTree = "<group>"; };
8472D2DF1EED3C5400E81232 /* Alamofire.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Alamofire.xcodeproj; path = Carthage/Checkouts/Alamofire/Alamofire.xcodeproj; sourceTree = "<group>"; };
84A389BA2233CCC200A0A66A /* keypathArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = keypathArray.json; sourceTree = "<group>"; };
84A389BB2233CCC200A0A66A /* keypathObject.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = keypathObject.json; sourceTree = "<group>"; };
84A389BC2233CCC200A0A66A /* object.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = object.json; sourceTree = "<group>"; };
84A389CA2233D9F500A0A66A /* emptyKeypath.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emptyKeypath.json; sourceTree = "<group>"; };
84A8C7FB1EED2E8600AB31BE /* CodableAlamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CodableAlamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
84A8C81A1EED2EB800AB31BE /* CodableAlamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CodableAlamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
84A8C8271EED2EC300AB31BE /* CodableAlamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CodableAlamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -200,6 +208,7 @@
children = (
8447D5CA1F77D54E003B32F3 /* LinuxMain.swift */,
8447D5D21F77D5BC003B32F3 /* MainTests.swift */,
84A389B92233CCC200A0A66A /* Mock */,
8447D5D31F77D5E2003B32F3 /* Supporting Files */,
);
path = Tests;
Expand Down Expand Up @@ -231,6 +240,17 @@
name = Products;
sourceTree = "<group>";
};
84A389B92233CCC200A0A66A /* Mock */ = {
isa = PBXGroup;
children = (
84A389BA2233CCC200A0A66A /* keypathArray.json */,
84A389BB2233CCC200A0A66A /* keypathObject.json */,
84A389BC2233CCC200A0A66A /* object.json */,
84A389CA2233D9F500A0A66A /* emptyKeypath.json */,
);
path = Mock;
sourceTree = "<group>";
};
84A8C7EF1EED2E4D00AB31BE = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -588,6 +608,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
84A389C72233CCC200A0A66A /* object.json in Resources */,
84A389C52233CCC200A0A66A /* keypathArray.json in Resources */,
84A389CB2233D9F500A0A66A /* emptyKeypath.json in Resources */,
84A389C62233CCC200A0A66A /* keypathObject.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
3 changes: 3 additions & 0 deletions Sources/CodableAlamofire/AlamofireDecodableError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import Foundation
///
/// - invalidKeyPath: Returned when a nested dictionary object doesn't exist by special keyPath.
/// - emptyKeyPath: Returned when a keyPath is empty.
/// - invalidJSON: Returned when a nested json is invalid.

public enum AlamofireDecodableError: Error {
case invalidKeyPath
case emptyKeyPath
case invalidJSON
}

extension AlamofireDecodableError: LocalizedError {
Expand All @@ -23,6 +25,7 @@ extension AlamofireDecodableError: LocalizedError {
switch self {
case .invalidKeyPath: return "Nested object doesn't exist by this keyPath."
case .emptyKeyPath: return "KeyPath can not be empty."
case .invalidJSON: return "Invalid nested json."
}
}
}
3 changes: 3 additions & 0 deletions Sources/CodableAlamofire/DataRequest+Decodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ extension DataRequest {
case .success(let json):
if let nestedJson = (json as AnyObject).value(forKeyPath: keyPath) {
do {
guard JSONSerialization.isValidJSONObject(nestedJson) else {
return .failure(AlamofireDecodableError.invalidJSON)
}
let data = try JSONSerialization.data(withJSONObject: nestedJson)
let object = try decoder.decode(T.self, from: data)
return .success(object)
Expand Down
34 changes: 27 additions & 7 deletions Tests/CodableAlamofireTests/MainTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ final class MainTests: XCTestCase {
]

func testResponseSimpleObject() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/object.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/object.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

let decoder = JSONDecoder()
Expand All @@ -64,7 +64,7 @@ final class MainTests: XCTestCase {
}

func testResponseArrayOfObjects() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/array.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/array.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

let decoder = JSONDecoder()
Expand Down Expand Up @@ -94,7 +94,7 @@ final class MainTests: XCTestCase {
}

func testResponseArrayOfObjectsByKeyPath() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/keypathArray.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/keypathArray.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

let decoder = JSONDecoder()
Expand Down Expand Up @@ -124,7 +124,7 @@ final class MainTests: XCTestCase {
}

func testResponseWithEmptyKeyPath() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/keypathArray.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/keypathArray.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

Alamofire.request(url).responseDecodableObject(keyPath: "") { (response: DataResponse<[Repo]>) in
Expand All @@ -144,7 +144,7 @@ final class MainTests: XCTestCase {
}

func testResponseWithInvalidKeyPath() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/keypathArray.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/keypathArray.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

Alamofire.request(url).responseDecodableObject(keyPath: "keypath") { (response: DataResponse<[Repo]>) in
Expand All @@ -164,7 +164,7 @@ final class MainTests: XCTestCase {
}

func testResponseWithWrongPropertyKeyObject() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/object.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/object.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

Alamofire.request(url).responseDecodableObject { (response: DataResponse<NotMappableRepo>) in
Expand All @@ -184,7 +184,7 @@ final class MainTests: XCTestCase {
}

func testResponseWithWrongPropertyKeyObjectByKeyPath() {
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/keypathObject.json")!
let url = URL(string: "https://raw.githubusercontent.com/otbivnoe/CodableAlamofire/master/Tests/Mock/keypathObject.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

Alamofire.request(url).responseDecodableObject(keyPath: "result.library") { (response: DataResponse<NotMappableRepo>) in
Expand All @@ -202,4 +202,24 @@ final class MainTests: XCTestCase {
XCTAssertNil(error)
}
}

func testResponseWithInvalidNestedJSONByKeypath() {
let url = URL(string: "https://raw.githubusercontent.com/Otbivnoe/CodableAlamofire/master/Tests/Mock/emptyKeypath.json")!
let expectation = self.expectation(description: "Reponse from \(url.absoluteString)")

Alamofire.request(url).responseDecodableObject(keyPath: "data") { (response: DataResponse<NotMappableRepo>) in
XCTAssertNotNil(response.error)
if case AlamofireDecodableError.invalidJSON = response.error! {
XCTAssertTrue(true)
}
else {
XCTAssertTrue(false)
}
expectation.fulfill()
}

waitForExpectations(timeout: 10) { error in
XCTAssertNil(error)
}
}
}
File renamed without changes.
3 changes: 3 additions & 0 deletions Tests/Mock/emptyKeypath.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"data": null
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 60e2c68

Please sign in to comment.