Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0.1
277 changes: 261 additions & 16 deletions DVR.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

99 changes: 99 additions & 0 deletions DVR.xcodeproj/xcshareddata/xcschemes/DVR-tvOS.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0810"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2104F52D1DC658580039CA14"
BuildableName = "DVR.framework"
BlueprintName = "DVR-tvOS"
ReferencedContainer = "container:DVR.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2104F5351DC658590039CA14"
BuildableName = "DVRTests.xctest"
BlueprintName = "DVRTests-tvOS"
ReferencedContainer = "container:DVR.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2104F52D1DC658580039CA14"
BuildableName = "DVR.framework"
BlueprintName = "DVR-tvOS"
ReferencedContainer = "container:DVR.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2104F52D1DC658580039CA14"
BuildableName = "DVR.framework"
BlueprintName = "DVR-tvOS"
ReferencedContainer = "container:DVR.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2104F52D1DC658580039CA14"
BuildableName = "DVR.framework"
BlueprintName = "DVR-tvOS"
ReferencedContainer = "container:DVR.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
26 changes: 13 additions & 13 deletions DVR/Cassette.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ struct Cassette {

// MARK: - Functions

func interactionForRequest(request: NSURLRequest) -> Interaction? {
func interactionForRequest(_ request: URLRequest) -> Interaction? {
for interaction in interactions {
let interactionRequest = interaction.request

// Note: We don't check headers right now
if interactionRequest.HTTPMethod == request.HTTPMethod && interactionRequest.URL == request.URL && interactionRequest.hasHTTPBodyEqualToThatOfRequest(request) {
if interactionRequest.httpMethod == request.httpMethod && interactionRequest.url == request.url && interactionRequest.hasHTTPBodyEqualToThatOfRequest(request) {
return interaction
}
}
Expand All @@ -33,34 +33,34 @@ struct Cassette {


extension Cassette {
var dictionary: [String: AnyObject] {
var dictionary: [String: Any] {
return [
"name": name,
"name": name as Any,
"interactions": interactions.map { $0.dictionary }
]
}

init?(dictionary: [String: AnyObject]) {
init?(dictionary: [String: Any]) {
guard let name = dictionary["name"] as? String else { return nil }

self.name = name

if let array = dictionary["interactions"] as? [[String: AnyObject]] {
if let array = dictionary["interactions"] as? [[String: Any]] {
interactions = array.flatMap { Interaction(dictionary: $0) }
} else {
interactions = []
}
}
}

private extension NSURLRequest {
func hasHTTPBodyEqualToThatOfRequest(request: NSURLRequest) -> Bool {
guard let body1 = self.HTTPBody,
body2 = request.HTTPBody,
encoded1 = Interaction.encodeBody(body1, headers: self.allHTTPHeaderFields),
encoded2 = Interaction.encodeBody(body2, headers: request.allHTTPHeaderFields)
private extension URLRequest {
func hasHTTPBodyEqualToThatOfRequest(_ request: URLRequest) -> Bool {
guard let body1 = self.httpBody,
let body2 = request.httpBody,
let encoded1 = Interaction.encodeBody(body1, headers: self.allHTTPHeaderFields),
let encoded2 = Interaction.encodeBody(body2, headers: request.allHTTPHeaderFields)
else {
return self.HTTPBody == request.HTTPBody
return self.httpBody == request.httpBody
}

return encoded1.isEqual(encoded2)
Expand Down
31 changes: 14 additions & 17 deletions DVR/URLHTTPResponse.swift → DVR/HTTPURLResponse.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import Foundation

// There isn't a mutable NSHTTPURLResponse, so we have to make our own.
class URLHTTPResponse: NSHTTPURLResponse {
// There isn't a mutable HTTPURLResponse, so we have to make our own.
class HTTPURLResponse: Foundation.HTTPURLResponse {
Copy link
Contributor

@sethhoward sethhoward Nov 3, 2016

Choose a reason for hiding this comment

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

If this code is not brought in via a pod (directly added to a project) which flavor of HTTPURLResponse will be used throughout the code base, Foundation or this? I would argue that this class should be prefixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can directly reference via the module, that is, either DVR.HTTPURLResponse or Foundation.HTTPURLResponse.

I think having it that way is most explicit and readable.


// MARK: - Properties

private var _URL: NSURL?
override var URL: NSURL? {
private var _url: URL?
override var url: URL? {
get {
return _URL ?? super.URL
return _url ?? super.url
}

set {
_URL = newValue
_url = newValue
}
}

Expand All @@ -27,8 +27,8 @@ class URLHTTPResponse: NSHTTPURLResponse {
}
}

private var _allHeaderFields: [NSObject : AnyObject]?
override var allHeaderFields: [NSObject : AnyObject] {
private var _allHeaderFields: [AnyHashable: Any]?
override var allHeaderFields: [AnyHashable: Any] {
get {
return _allHeaderFields ?? super.allHeaderFields
}
Expand All @@ -40,8 +40,8 @@ class URLHTTPResponse: NSHTTPURLResponse {
}


extension NSHTTPURLResponse {
override var dictionary: [String: AnyObject] {
extension Foundation.HTTPURLResponse {
override var dictionary: [String: Any] {
var dictionary = super.dictionary

dictionary["headers"] = allHeaderFields
Expand All @@ -52,13 +52,10 @@ extension NSHTTPURLResponse {
}


extension URLHTTPResponse {
convenience init(dictionary: [String: AnyObject]) {
self.init()

if let string = dictionary["url"] as? String, url = NSURL(string: string) {
URL = url
}
extension HTTPURLResponse {
convenience init(dictionary: [String: Any]) {
let url = URL(string: dictionary["url"] as! String)!
self.init(url: url, mimeType: nil, expectedContentLength: 0, textEncodingName: nil)

if let headers = dictionary["headers"] as? [String: String] {
allHeaderFields = headers
Expand Down
48 changes: 24 additions & 24 deletions DVR/Interaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ struct Interaction {

// MARK: - Properties

let request: NSURLRequest
let response: NSURLResponse
let responseData: NSData?
let recordedAt: NSDate
let request: URLRequest
let response: Foundation.URLResponse
let responseData: Data?
let recordedAt: Date


// MARK: - Initializers

init(request: NSURLRequest, response: NSURLResponse, responseData: NSData? = nil, recordedAt: NSDate = NSDate()) {
init(request: URLRequest, response: Foundation.URLResponse, responseData: Data? = nil, recordedAt: Date = Date()) {
self.request = request
self.response = response
self.responseData = responseData
Expand All @@ -22,42 +22,42 @@ struct Interaction {

// MARK: - Encoding

static func encodeBody(body: NSData, headers: [String: String]? = nil) -> AnyObject? {
static func encodeBody(_ body: Data, headers: [String: String]? = nil) -> AnyObject? {
if let contentType = headers?["Content-Type"] {
// Text
if contentType.hasPrefix("text/") {
// TODO: Use text encoding if specified in headers
return NSString(data: body, encoding: NSUTF8StringEncoding)
return NSString(data: body, encoding: String.Encoding.utf8.rawValue)
}

// JSON
if contentType.hasPrefix("application/json") {
do {
return try NSJSONSerialization.JSONObjectWithData(body, options: [])
return try JSONSerialization.jsonObject(with: body, options: []) as AnyObject
} catch {
return nil
}
}
}

// Base64
return body.base64EncodedStringWithOptions([])
return body.base64EncodedString(options: []) as AnyObject?
}

static func dencodeBody(body: AnyObject?, headers: [String: String]? = nil) -> NSData? {
static func dencodeBody(_ body: Any?, headers: [String: String]? = nil) -> Data? {
guard let body = body else { return nil }

if let contentType = headers?["Content-Type"] {
// Text
if let string = body as? String where contentType.hasPrefix("text/") {
if let string = body as? String , contentType.hasPrefix("text/") {
// TODO: Use encoding if specified in headers
return string.dataUsingEncoding(NSUTF8StringEncoding)
return string.data(using: String.Encoding.utf8)
}

// JSON
if contentType.hasPrefix("application/json") {
do {
return try NSJSONSerialization.dataWithJSONObject(body, options: [])
return try JSONSerialization.data(withJSONObject: body, options: [])
} catch {
return nil
}
Expand All @@ -66,7 +66,7 @@ struct Interaction {

// Base64
if let base64 = body as? String {
return NSData(base64EncodedString: base64, options: [])
return Data(base64Encoded: base64, options: [])
}

return nil
Expand All @@ -75,29 +75,29 @@ struct Interaction {


extension Interaction {
var dictionary: [String: AnyObject] {
var dictionary: [String: AnyObject] = [
var dictionary: [String: Any] {
var dictionary: [String: Any] = [
"request": request.dictionary,
"recorded_at": recordedAt.timeIntervalSince1970
]

var response = self.response.dictionary
if let data = responseData, body = Interaction.encodeBody(data, headers: response["headers"] as? [String: String]) {
if let data = responseData, let body = Interaction.encodeBody(data, headers: response["headers"] as? [String: String]) {
response["body"] = body
}
dictionary["response"] = response

return dictionary
}

init?(dictionary: [String: AnyObject]) {
guard let request = dictionary["request"] as? [String: AnyObject],
response = dictionary["response"] as? [String: AnyObject],
recordedAt = dictionary["recorded_at"] as? Int else { return nil }
init?(dictionary: [String: Any]) {
guard let request = dictionary["request"] as? [String: Any],
let response = dictionary["response"] as? [String: Any],
let recordedAt = dictionary["recorded_at"] as? Int else { return nil }

self.request = NSMutableURLRequest(dictionary: request)
self.response = URLHTTPResponse(dictionary: response)
self.recordedAt = NSDate(timeIntervalSince1970: NSTimeInterval(recordedAt))
self.request = NSMutableURLRequest(dictionary: request) as URLRequest
self.response = HTTPURLResponse(dictionary: response)
self.recordedAt = Date(timeIntervalSince1970: TimeInterval(recordedAt))
self.responseData = Interaction.dencodeBody(response["body"], headers: response["headers"] as? [String: String])
}
}
2 changes: 1 addition & 1 deletion DVR/Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.0</string>
<string>0.4.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
Loading