Skip to content

Implementation of URLSessionTask '.error', NSCopying #713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 15, 2016
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Docs/Status.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ There is no _Complete_ status for test coverage because there are always additio
| `URLSession` | Mostly Complete | Incomplete | `shared`, invalidation, resetting, flushing, getting tasks, and others remain unimplemented |
| `URLSessionConfiguration` | Mostly Complete | Incomplete | `ephemeral` and `background(withIdentifier:)` remain unimplemented |
| `URLSessionDelegate` | Complete | N/A | |
| `URLSessionTask` | Mostly Complete | Incomplete | `NSCopying`, `cancel()`, `error`, `createTransferState(url:)` with streams, and others remain unimplemented |
| `URLSessionTask` | Mostly Complete | Incomplete | `cancel()`, `createTransferState(url:)` with streams, and others remain unimplemented |
| `URLSessionDataTask` | Complete | Incomplete | |
| `URLSessionUploadTask` | Complete | None | |
| `URLSessionDownloadTask` | Incomplete | Incomplete | `cancel(byProducingResumeData:)` remains unimplemented |
Expand Down
10 changes: 6 additions & 4 deletions Foundation/NSURLSession/NSURLSessionTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ open class URLSessionTask : NSObject, NSCopying {
}

open func copy(with zone: NSZone?) -> Any {
NSUnimplemented()
return self
}

/// An identifier for this task, assigned by and unique to the owning session
Expand Down Expand Up @@ -221,7 +221,7 @@ open class URLSessionTask : NSObject, NSCopying {
* The error, if any, delivered via -URLSession:task:didCompleteWithError:
* This property will be nil in the event that no error occured.
*/
/*@NSCopying*/ open var error: NSError? { NSUnimplemented() }
/*@NSCopying*/ open fileprivate(set) var error: NSError?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that we can keep this fileprivate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows to set error without creating a backing private property.
The other option is to create fileprivate var _error: Error? and make error a get only computed property.


/// Suspend the task.
///
Expand Down Expand Up @@ -877,6 +877,8 @@ extension URLSessionTask {
}
}
func completeTask(withError error: NSError) {
self.error = error

guard case .transferFailed = internalState else {
fatalError("Trying to complete the task, but its transfer isn't complete / failed.")
}
Expand Down Expand Up @@ -1032,8 +1034,8 @@ fileprivate extension URLSessionTask {
guard case .waitingForResponseCompletionHandler(let ts) = internalState else { fatalError("Received response disposition, but we're not waiting for it.") }
switch disposition {
case .cancel:
//TODO: Fail the task with NSURLErrorCancelled
NSUnimplemented()
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled)
self.completeTask(withError: error)
case .allow:
// Continue the transfer. This will unpause the easy handle.
internalState = .transferInProgress(ts)
Expand Down
37 changes: 36 additions & 1 deletion TestFoundation/TestNSURLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class TestURLSession : XCTestCase {
("test_downloadTaskWithURLRequest", test_downloadTaskWithURLRequest),
("test_downloadTaskWithRequestAndHandler", test_downloadTaskWithRequestAndHandler),
("test_downloadTaskWithURLAndHandler", test_downloadTaskWithURLAndHandler),
("test_finishTaskAndInvalidate", test_finishTasksAndInvalidate)
("test_finishTaskAndInvalidate", test_finishTasksAndInvalidate),
("test_taskError", test_taskError),
("test_taskCopy", test_taskCopy),
]
}

Expand Down Expand Up @@ -262,6 +264,39 @@ class TestURLSession : XCTestCase {
session.finishTasksAndInvalidate()
waitForExpectations(timeout: 12)
}

func test_taskError() {
let url = URL(string: "http://127.0.0.1:\(serverPort)/Nepal")!
let session = URLSession(configuration: URLSessionConfiguration.default,
delegate: nil,
delegateQueue: nil)
let completionExpectation = expectation(description: "dataTask completion block wasn't called")
let task = session.dataTask(with: url) { result in
let error = result.2
XCTAssertNotNil(error)
XCTAssertEqual(error?.code, NSURLErrorBadURL)
completionExpectation.fulfill()
}
//should result in Bad URL error
task.resume()

waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)

XCTAssertNotNil(task.error)
XCTAssertEqual(task.error?.code, NSURLErrorBadURL)
}
}

func test_taskCopy() {
let url = URL(string: "http://127.0.0.1:\(serverPort)/Nepal")!
let session = URLSession(configuration: URLSessionConfiguration.default,
delegate: nil,
delegateQueue: nil)
let task = session.dataTask(with: url)

XCTAssert(task.isEqual(task.copy()))
}
}

class SessionDelegate: NSObject, URLSessionDelegate {
Expand Down