Skip to content

Commit db66211

Browse files
committed
Add support for extracting recorded requests
1 parent d4551da commit db66211

3 files changed

Lines changed: 67 additions & 27 deletions

File tree

MockDuck/Sources/MockBundle.swift

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,65 @@ final class MockBundle {
5555
os_log("Request %@ not found on disk. Expected file name: %@", log: MockDuck.log, type: .debug, "\(request)", fileName)
5656
}
5757

58-
if
59-
let targetURL = targetURL,
60-
let targetLoadingURL = targetLoadingURL
61-
{
62-
let decoder = JSONDecoder()
63-
64-
do {
65-
let data = try Data(contentsOf: targetURL)
66-
67-
let loaded = try decoder.decode(MockRequestResponse.self, from: data)
68-
requestResponse.responseWrapper = loaded.responseWrapper
58+
if let loadedResponse = loadResponseFile(targetURL: targetURL) {
59+
requestResponse.responseWrapper = loadedResponse.responseWrapper
60+
requestResponse.responseData = loadedResponse.responseData
61+
}
6962

70-
// Load the response data if the format is supported.
71-
// This should be the same filename with a different extension.
72-
if let dataFileName = requestResponse.fileName(for: .responseData) {
73-
let dataURL = targetLoadingURL.appendingPathComponent(dataFileName)
74-
requestResponse.responseData = try Data(contentsOf: dataURL)
63+
return false
64+
}
65+
66+
func loadResponseFile(targetURL: URL?) -> MockRequestResponse? {
67+
guard let targetURL = targetURL else { return nil }
68+
let decoder = JSONDecoder()
69+
70+
do {
71+
let data = try Data(contentsOf: targetURL)
72+
73+
var response = try decoder.decode(MockRequestResponse.self, from: data)
74+
75+
// Load the response data if the format is supported.
76+
// This should be the same fil ename with a different extension.
77+
if let dataFileName = response.fileName(for: .responseData) {
78+
let dataURL = targetURL.deletingLastPathComponent().appendingPathComponent(dataFileName)
79+
response.responseData = try? Data(contentsOf: dataURL)
80+
}
81+
82+
return response
83+
} catch {
84+
os_log("Error decoding JSON: %@", log: MockDuck.log, type: .error, "\(error)")
85+
}
86+
return nil
87+
}
88+
89+
func getResponses(for hostname: String) -> [MockRequestResponse] {
90+
guard let baseURL = recordingURL else { return [] }
91+
92+
var responses = [MockRequestResponse]()
93+
let targetURL = baseURL.appendingPathComponent(hostname)
94+
95+
let results = FileManager.default.enumerator(
96+
at: targetURL,
97+
includingPropertiesForKeys: [.isDirectoryKey],
98+
options: [])
99+
if let results = results {
100+
for item in results {
101+
var isDir = ObjCBool(false)
102+
if
103+
let item = item as? URL,
104+
let attributes = try? FileManager.default.fileExists(
105+
atPath: item.path,
106+
isDirectory: &isDir),
107+
!isDir.boolValue,
108+
!item.lastPathComponent.contains("-response"),
109+
let response = loadResponseFile(targetURL: item)
110+
{
111+
responses.append(response)
75112
}
76-
77-
return true
78-
} catch {
79-
os_log("Error decoding JSON: %@", log: MockDuck.log, type: .error, "\(error)")
80113
}
81114
}
82-
83-
return false
115+
116+
return responses
84117
}
85118

86119
/// If recording is enabled, this method saves the request to the filesystem. If the request

MockDuck/Sources/MockDuck.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ public final class MockDuck {
135135
public static func unregisterAllRequestHandlers() {
136136
mockBundle.unregisterAllRequestHandlers()
137137
}
138+
139+
// MARK: - Fetching Response Objects
140+
141+
public static func getResponses(for hostname: String) -> [MockRequestResponse] {
142+
checkConfigureMockDuck()
143+
return mockBundle.getResponses(for: hostname)
144+
}
138145

139146
// MARK: - Internal Use Only
140147

MockDuck/Sources/MockRequestResponse.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import Foundation
1010

1111
/// A basic container for holding a request, a response, and any associated data.
12-
final class MockRequestResponse: Codable, CustomDebugStringConvertible {
12+
public final class MockRequestResponse: Codable, CustomDebugStringConvertible {
1313

1414
enum MockFileTarget {
1515
case request
@@ -19,7 +19,7 @@ final class MockRequestResponse: Codable, CustomDebugStringConvertible {
1919

2020
// MARK: - Properties
2121

22-
var request: URLRequest {
22+
public var request: URLRequest {
2323
get {
2424
return requestWrapper.request
2525
}
@@ -28,11 +28,11 @@ final class MockRequestResponse: Codable, CustomDebugStringConvertible {
2828
}
2929
}
3030

31-
var response: URLResponse? {
31+
public var response: URLResponse? {
3232
return responseWrapper?.response
3333
}
3434

35-
var responseData: Data? {
35+
public var responseData: Data? {
3636
get {
3737
return responseWrapper?.responseData
3838
}
@@ -140,7 +140,7 @@ final class MockRequestResponse: Codable, CustomDebugStringConvertible {
140140
case responseWrapper = "response"
141141
}
142142

143-
init(from decoder: Decoder) throws {
143+
public init(from decoder: Decoder) throws {
144144
let container = try decoder.container(keyedBy: CodingKeys.self)
145145
requestWrapper = try container.decode(MockRequest.self, forKey: .requestWrapper)
146146
responseWrapper = try container.decodeIfPresent(MockResponse.self, forKey: .responseWrapper)

0 commit comments

Comments
 (0)