-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Wes Billman
committed
May 20, 2017
1 parent
933472a
commit f88df37
Showing
5 changed files
with
231 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// Created by Wes Billman on 5/20/17. | ||
// Copyright © 2017 wesbillman. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
public enum JSONFeedReaderError: Error { | ||
case invalidRequestString | ||
case emptyResponseData | ||
} | ||
|
||
public class JSONFeedReader { | ||
private let session: URLSession | ||
|
||
init(session: URLSession = URLSession(configuration: URLSessionConfiguration.default)) { | ||
self.session = session | ||
} | ||
|
||
public func read(url: URL, complete: @escaping (JSONFeed?, Error?) -> Void) { | ||
let task = session.dataTask(with: URLRequest(url: url)) { (data, _, error) in | ||
if let error = error { | ||
complete(nil, error) | ||
return | ||
} | ||
guard let data = data else { | ||
complete(nil, JSONFeedReaderError.emptyResponseData) | ||
return | ||
} | ||
do { | ||
let feed = try JSONFeed(data: data) | ||
complete(feed, nil) | ||
} catch { | ||
complete(nil, error) | ||
} | ||
} | ||
task.resume() | ||
} | ||
|
||
public func read(string: String, complete: @escaping (JSONFeed?, Error?) -> Void) { | ||
guard let url = URL(string: string) else { | ||
complete(nil, JSONFeedReaderError.invalidRequestString) | ||
return | ||
} | ||
read(url: url, complete: complete) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// | ||
// Created by Wes Billman on 5/20/17. | ||
// Copyright © 2017 wesbillman. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import JSONFeed | ||
|
||
class JSONFeedReaderTests: XCTestCase { | ||
enum TestError: Error { | ||
case sessionError | ||
} | ||
|
||
private let url = "https://jsonfeed.org/version/1" | ||
private let text = "Some Text" | ||
|
||
private var session: MockURLSession! | ||
private var subject: JSONFeedReader! | ||
|
||
var validData: Data { | ||
let json = ["version": url, "title": text] | ||
guard let data = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) else { | ||
return Data() | ||
} | ||
return data | ||
} | ||
|
||
override func setUp() { | ||
super.setUp() | ||
session = MockURLSession() | ||
subject = JSONFeedReader(session: session) | ||
} | ||
|
||
func testInvalidURLString() { | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
let nilString: String? = nil | ||
|
||
subject.read(string: "bogus\\\(String(describing: nilString))") { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(!session.task.resumed) | ||
XCTAssertEqual(resultError as? JSONFeedReaderError, JSONFeedReaderError.invalidRequestString) | ||
XCTAssertNil(resultFeed) | ||
} | ||
|
||
func testSessionError() { | ||
session.error = TestError.sessionError | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
|
||
subject.read(string: "example.com") { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(session.task.resumed) | ||
XCTAssertEqual(resultError as? TestError, TestError.sessionError) | ||
XCTAssertNil(resultFeed) | ||
} | ||
|
||
func testNilData() { | ||
session.data = nil | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
|
||
subject.read(string: "example.com") { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(session.task.resumed) | ||
XCTAssertEqual(resultError as? JSONFeedReaderError, JSONFeedReaderError.emptyResponseData) | ||
XCTAssertNil(resultFeed) | ||
} | ||
|
||
func testInvalidData() { | ||
guard let data = "bogus".data(using: .utf8) else { | ||
XCTFail() | ||
return | ||
} | ||
session.data = data | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
|
||
subject.read(string: "example.com") { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(session.task.resumed) | ||
XCTAssertEqual(resultError as? JSONFeedError, JSONFeedError.invalidData) | ||
XCTAssertNil(resultFeed) | ||
} | ||
|
||
func testReadingFeedURL() { | ||
session.data = validData | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
|
||
guard let feedUrl = URL(string: "example.com") else { | ||
XCTFail("unable to create url") | ||
return | ||
} | ||
|
||
subject.read(url: feedUrl) { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(session.task.resumed) | ||
XCTAssertEqual(resultFeed?.version.absoluteString, url) | ||
XCTAssertEqual(resultFeed?.title, text) | ||
XCTAssertNil(resultError) | ||
} | ||
|
||
func testReadingFeedURLString() { | ||
session.data = validData | ||
var resultFeed: JSONFeed? = nil | ||
var resultError: Error? = nil | ||
|
||
subject.read(string: "example.com") { (feed, error) in | ||
resultFeed = feed | ||
resultError = error | ||
} | ||
XCTAssert(session.task.resumed) | ||
XCTAssertEqual(resultFeed?.version.absoluteString, url) | ||
XCTAssertEqual(resultFeed?.title, text) | ||
XCTAssertNil(resultError) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// Created by Wes Billman on 5/20/17. | ||
// Copyright © 2017 wesbillman. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
class MockURLSession: URLSession { | ||
let task = MockURLSessionDataTask() | ||
var data: Data? | ||
var response: URLResponse? | ||
var error: Error? | ||
|
||
override func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { | ||
completionHandler(data, response, error) | ||
return task | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
// Created by Wes Billman on 5/20/17. | ||
// Copyright © 2017 wesbillman. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
class MockURLSessionDataTask: URLSessionDataTask { | ||
private(set) var resumed = false | ||
override func resume() { | ||
resumed = true | ||
} | ||
} |