Skip to content

Commit 82391ec

Browse files
authored
Merge pull request #3 from WeTransfer/feature/improvements
Mocker improvements
2 parents ece822f + 67ff201 commit 82391ec

12 files changed

+221
-47
lines changed

Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source "https://rubygems.org"
33

44
gem 'danger'
5-
gem 'danger-swiftlint'
5+
gem 'danger-swiftlint', '0.9.0'
66
gem 'danger-xcov'
77
gem 'danger-xcodebuild'
88
gem 'danger-xcode_summary'

Mocker.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |spec|
22
spec.name = 'Mocker'
3-
spec.version = '1.0.0'
3+
spec.version = '1.1.0'
44
spec.summary = 'Mock data requests using a custom URLProtocol and run them offline.'
55
spec.description = 'Mocker is a library written in Swift which makes it possible to mock data requests using a custom URLProtocol and run them offline.'
66

Mocker.xcodeproj/project.pbxproj

+19-5
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,19 @@
177177
isa = PBXProject;
178178
attributes = {
179179
LastSwiftUpdateCheck = 0830;
180-
LastUpgradeCheck = 0830;
180+
LastUpgradeCheck = 0900;
181181
ORGANIZATIONNAME = WeTransfer;
182182
TargetAttributes = {
183183
501E26931F3DAE370048F39E = {
184184
CreatedOnToolsVersion = 8.3.3;
185185
DevelopmentTeam = GLJTT4T544;
186+
LastSwiftMigration = 0900;
186187
ProvisioningStyle = Automatic;
187188
};
188189
501E269C1F3DAE370048F39E = {
189190
CreatedOnToolsVersion = 8.3.3;
190191
DevelopmentTeam = GLJTT4T544;
192+
LastSwiftMigration = 0900;
191193
ProvisioningStyle = Automatic;
192194
};
193195
};
@@ -285,15 +287,21 @@
285287
CLANG_CXX_LIBRARY = "libc++";
286288
CLANG_ENABLE_MODULES = YES;
287289
CLANG_ENABLE_OBJC_ARC = YES;
290+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
288291
CLANG_WARN_BOOL_CONVERSION = YES;
292+
CLANG_WARN_COMMA = YES;
289293
CLANG_WARN_CONSTANT_CONVERSION = YES;
290294
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
291295
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
292296
CLANG_WARN_EMPTY_BODY = YES;
293297
CLANG_WARN_ENUM_CONVERSION = YES;
294298
CLANG_WARN_INFINITE_RECURSION = YES;
295299
CLANG_WARN_INT_CONVERSION = YES;
300+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
301+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
296302
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
303+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
304+
CLANG_WARN_STRICT_PROTOTYPES = YES;
297305
CLANG_WARN_SUSPICIOUS_MOVE = YES;
298306
CLANG_WARN_UNREACHABLE_CODE = YES;
299307
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -323,6 +331,7 @@
323331
SDKROOT = iphoneos;
324332
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
325333
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
334+
SWIFT_VERSION = 4.0;
326335
TARGETED_DEVICE_FAMILY = "1,2";
327336
VERSIONING_SYSTEM = "apple-generic";
328337
VERSION_INFO_PREFIX = "";
@@ -339,15 +348,21 @@
339348
CLANG_CXX_LIBRARY = "libc++";
340349
CLANG_ENABLE_MODULES = YES;
341350
CLANG_ENABLE_OBJC_ARC = YES;
351+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
342352
CLANG_WARN_BOOL_CONVERSION = YES;
353+
CLANG_WARN_COMMA = YES;
343354
CLANG_WARN_CONSTANT_CONVERSION = YES;
344355
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
345356
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
346357
CLANG_WARN_EMPTY_BODY = YES;
347358
CLANG_WARN_ENUM_CONVERSION = YES;
348359
CLANG_WARN_INFINITE_RECURSION = YES;
349360
CLANG_WARN_INT_CONVERSION = YES;
361+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
362+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
350363
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
364+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
365+
CLANG_WARN_STRICT_PROTOTYPES = YES;
351366
CLANG_WARN_SUSPICIOUS_MOVE = YES;
352367
CLANG_WARN_UNREACHABLE_CODE = YES;
353368
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -369,6 +384,7 @@
369384
MTL_ENABLE_DEBUG_INFO = NO;
370385
SDKROOT = iphoneos;
371386
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
387+
SWIFT_VERSION = 4.0;
372388
TARGETED_DEVICE_FAMILY = "1,2";
373389
VALIDATE_PRODUCT = YES;
374390
VERSIONING_SYSTEM = "apple-generic";
@@ -391,7 +407,6 @@
391407
PRODUCT_BUNDLE_IDENTIFIER = com.wetransfer.Mocker;
392408
PRODUCT_NAME = "$(TARGET_NAME)";
393409
SKIP_INSTALL = YES;
394-
SWIFT_VERSION = 3.0;
395410
};
396411
name = Debug;
397412
};
@@ -410,7 +425,6 @@
410425
PRODUCT_BUNDLE_IDENTIFIER = com.wetransfer.Mocker;
411426
PRODUCT_NAME = "$(TARGET_NAME)";
412427
SKIP_INSTALL = YES;
413-
SWIFT_VERSION = 3.0;
414428
};
415429
name = Release;
416430
};
@@ -423,7 +437,7 @@
423437
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
424438
PRODUCT_BUNDLE_IDENTIFIER = com.wetransfer.MockerTests;
425439
PRODUCT_NAME = "$(TARGET_NAME)";
426-
SWIFT_VERSION = 3.0;
440+
SWIFT_SWIFT3_OBJC_INFERENCE = On;
427441
};
428442
name = Debug;
429443
};
@@ -436,7 +450,7 @@
436450
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
437451
PRODUCT_BUNDLE_IDENTIFIER = com.wetransfer.MockerTests;
438452
PRODUCT_NAME = "$(TARGET_NAME)";
439-
SWIFT_VERSION = 3.0;
453+
SWIFT_SWIFT3_OBJC_INFERENCE = On;
440454
};
441455
name = Release;
442456
};

Mocker.xcodeproj/xcshareddata/xcschemes/Mocker.xcscheme

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "0830"
3+
LastUpgradeVersion = "0900"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
language = ""
2930
shouldUseLaunchSchemeArgsEnv = "YES"
3031
codeCoverageEnabled = "YES">
3132
<Testables>
@@ -56,6 +57,7 @@
5657
buildConfiguration = "Debug"
5758
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
5859
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
60+
language = ""
5961
launchStyle = "0"
6062
useCustomWorkingDirectory = "NO"
6163
ignoresPersistentStateOnLaunch = "NO"

Mocker/MockerTests/.swiftlint.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ disabled_rules: # Rule identifiers to exclude from running
33
- identifier_name
44
- force_cast
55
- force_try
6+
- force_unwrapping
67
opt_in_rules:
78
- empty_count
89
- explicit_init

Mocker/MockerTests/MockedData.swift

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import UIKit
1313
public final class MockedData {
1414
public static let botAvatarImageFileUrl: URL = Bundle(for: MockedData.self).url(forResource: "wetransfer_bot_avater", withExtension: "png")!
1515
public static let exampleJSON: URL = Bundle(for: MockedData.self).url(forResource: "Resources/JSON Files/example", withExtension: "json")!
16+
public static let redirectGET: URL = Bundle(for: MockedData.self).url(forResource: "Resources/sample-redirect-get", withExtension: "data")!
1617
}
1718

1819
internal extension URL {

Mocker/MockerTests/MockerTests.swift

+63-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class MockerTests: XCTestCase {
2525
let expectation = self.expectation(description: "Data request should succeed")
2626
let originalURL = URL(string: "https://avatars3.githubusercontent.com/u/26250426?v=4&s=400")!
2727

28-
let mock = Mock(url: originalURL, contentType: .imagePNG, statusCode: 200, data: [
28+
let mock = Mock(url: originalURL, dataType: .imagePNG, statusCode: 200, data: [
2929
.get: MockedData.botAvatarImageFileUrl.data
3030
])
3131

@@ -47,7 +47,7 @@ final class MockerTests: XCTestCase {
4747
let expectation = self.expectation(description: "Data request should succeed")
4848
let originalURL = URL(string: "https://www.wetransfer.com/sample-image.png")
4949

50-
Mock(fileExtensions: "png", contentType: .imagePNG, statusCode: 200, data: [
50+
Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 200, data: [
5151
.get: MockedData.botAvatarImageFileUrl.data
5252
]).register()
5353

@@ -68,7 +68,7 @@ final class MockerTests: XCTestCase {
6868
let expectation = self.expectation(description: "Data request should succeed")
6969
let originalURL = URL(string: "https://www.wetransfer.com/example.json")!
7070

71-
Mock(url: originalURL, contentType: .json, statusCode: 200, data: [
71+
Mock(url: originalURL, dataType: .json, statusCode: 200, data: [
7272
.get: MockedData.exampleJSON.data
7373
]
7474
).register()
@@ -95,7 +95,7 @@ final class MockerTests: XCTestCase {
9595
func testAdditionalHeaders() {
9696
let expectation = self.expectation(description: "Data request should succeed")
9797
let headers = ["testkey": "testvalue"]
98-
let mock = Mock(contentType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: headers)
98+
let mock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: headers)
9999
mock.register()
100100

101101
URLSession.shared.dataTask(with: mock.url) { (_, response, error) in
@@ -110,10 +110,10 @@ final class MockerTests: XCTestCase {
110110
/// It should override existing mocks.
111111
func testMockOverriding() {
112112
let expectation = self.expectation(description: "Data request should succeed")
113-
let mock = Mock(contentType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["testkey": "testvalue"])
113+
let mock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["testkey": "testvalue"])
114114
mock.register()
115115

116-
let newMock = Mock(contentType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["newkey": "newvalue"])
116+
let newMock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["newkey": "newvalue"])
117117
newMock.register()
118118

119119
URLSession.shared.dataTask(with: mock.url) { (_, response, error) in
@@ -130,7 +130,7 @@ final class MockerTests: XCTestCase {
130130
let expectation = self.expectation(description: "Data request should succeed")
131131
let originalURL = URL(string: "https://www.wetransfer.com/sample-image.png")
132132

133-
Mock(fileExtensions: "png", contentType: .imagePNG, statusCode: 200, data: [
133+
Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 200, data: [
134134
.get: MockedData.botAvatarImageFileUrl.data
135135
]).register()
136136

@@ -149,4 +149,60 @@ final class MockerTests: XCTestCase {
149149

150150
waitForExpectations(timeout: 10.0, handler: nil)
151151
}
152+
153+
/// It should be possible to test cancellation of requests with a delayed mock.
154+
func testDelayedMock() {
155+
let expectation = self.expectation(description: "Data request should be cancelled")
156+
var mock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()])
157+
mock.delay = DispatchTimeInterval.seconds(5)
158+
mock.register()
159+
160+
let task = URLSession.shared.dataTask(with: mock.url) { (_, _, error) in
161+
XCTAssert(error?._code == NSURLErrorCancelled)
162+
expectation.fulfill()
163+
}
164+
165+
task.resume()
166+
167+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
168+
task.cancel()
169+
})
170+
171+
waitForExpectations(timeout: 10.0, handler: nil)
172+
}
173+
174+
/// It should correctly handle redirect responses.
175+
func testRedirectResponse() {
176+
let expectation = self.expectation(description: "Data request should be cancelled")
177+
let urlWhichRedirects: URL = URL(string: "https://we.tl/redirect")!
178+
Mock(url: urlWhichRedirects, dataType: .html, statusCode: 200, data: [.get: MockedData.redirectGET.data]).register()
179+
Mock(url: URL(string: "https://wetransfer.com/redirect")!, dataType: .json, statusCode: 200, data: [.get: MockedData.exampleJSON.data]).register()
180+
181+
URLSession.shared.dataTask(with: urlWhichRedirects) { (data, _, _) in
182+
183+
guard let data = data, let jsonDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
184+
XCTFail("Wrong data response")
185+
expectation.fulfill()
186+
return
187+
}
188+
189+
let framework = Framework(jsonDictionary: jsonDictionary)
190+
XCTAssert(framework.name == "Mocker")
191+
XCTAssert(framework.owner == "WeTransfer")
192+
193+
expectation.fulfill()
194+
}.resume()
195+
196+
waitForExpectations(timeout: 10.0, handler: nil)
197+
}
198+
199+
/// It should be possible to ignore URLs and not let them be handled.
200+
func testIgnoreURLs() {
201+
202+
let ignoredURL = URL(string: "www.wetransfer.com")!
203+
204+
XCTAssert(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)) == true)
205+
Mocker.ignore(ignoredURL)
206+
XCTAssert(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)) == false)
207+
}
152208
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
HTTP/1.1 302 Moved Temporarily
2+
Content-Type: text/html;charset=utf-8
3+
Content-Length: 0
4+
Cache-Control: public
5+
Date: Tue, 10 Oct 2017 07:28:33 GMT
6+
Location: https://wetransfer.com/redirect
7+
Server: nginx/1.12.0
8+
X-Content-Type-Options: nosniff
9+
X-Request-Id: 8c43587ec891b2f1f72c61ecec2e96db
10+
X-XSS-Protection: 1; mode=block
11+
X-Cache: Miss from cloudfront
12+
Via: 1.1 72f202fb973968c0cfdb028ab6f36fac.cloudfront.net (CloudFront)
13+
X-Amz-Cf-Id: tU8eVZ9jWBJzd3aEB-4gyym_VxcPKskWFByEvXapy5WrdDkV-35-KA==
14+
Connection: Keep-alive

README.md

+45-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
</p>
44

55
<p align="center">
6-
<img src="https://travis-ci.org/WeTransfer/Mocker.svg?branch=master"/>
6+
<img src="https://api.travis-ci.org/WeTransfer/Mocker.svg?branch=master"/>
77
<img src="https://img.shields.io/cocoapods/v/Mocker.svg?style=flat"/>
88
<img src="https://img.shields.io/cocoapods/l/Mocker.svg?style=flat"/>
99
<img src="https://img.shields.io/cocoapods/p/Mocker.svg?style=flat"/>
10+
<img src="https://img.shields.io/badge/language-swift4.0-f48041.svg?style=flat"/>
1011
<img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"/>
1112
<img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=flat"/>
1213
</p>
@@ -25,6 +26,9 @@ Mocker is a library written in Swift which makes it possible to mock data reques
2526
- [JSON Requests](#json-requests)
2627
- [File extensions](#file-extensions)
2728
- [Custom HEAD and GET response](#custom-head-and-get-response)
29+
- [Delayed responses](#delayed-responses)
30+
- [Redirect responses](#redirect-responses)
31+
- [Ignoring URLs](#ignoring-urls)
2832
- [Communication](#communication)
2933
- [Installation](#installation)
3034
- [Release Notes](#release-notes)
@@ -39,9 +43,9 @@ _Run all your data request unit tests offline_ 🎉
3943
- [x] Supports popular frameworks like `Alamofire`
4044

4145
## Requirements
42-
- Swift 3.0, 3.1, 3.2
46+
- Swift 3+
4347
- iOS 8.0+
44-
- Xcode 8.1, 8.2, 8.3
48+
- Xcode 9.0+
4549

4650
## Usage
4751

@@ -127,6 +131,44 @@ URLSession.shared.dataTask(with: exampleURL) { (data, response, error) in
127131
}.resume()
128132
```
129133

134+
##### Delayed responses
135+
Sometimes you want to test if cancellation of requests is working. In that case, the mocked request should not finished directly and you need an delay. This can be added easily:
136+
137+
```swift
138+
let exampleURL = URL(string: "https://www.wetransfer.com/api/endpoint")!
139+
140+
var mock = Mock(url: exampleURL, contentType: .json, statusCode: 200, data: [
141+
.head: MockedData.headResponse.data,
142+
.get: MockedData.exampleJSON.data
143+
])
144+
mock.delay = DispatchTimeInterval.seconds(5)
145+
mock.register()
146+
```
147+
148+
##### Redirect responses
149+
Sometimes you want to mock short URLs or other redirect URLs. This is possible by saving the response and mock the redirect location, which can be found inside the response:
150+
151+
```
152+
Date: Tue, 10 Oct 2017 07:28:33 GMT
153+
Location: https://wetransfer.com/redirect
154+
```
155+
156+
By creating a mock for the short URL and the redirect URL, you can mock redirect and test this behaviour:
157+
158+
```swift
159+
let urlWhichRedirects: URL = URL(string: "https://we.tl/redirect")!
160+
Mock(url: urlWhichRedirects, dataType: .html, statusCode: 200, data: [.get: MockedData.redirectGET.data]).register()
161+
Mock(url: URL(string: "https://wetransfer.com/redirect")!, dataType: .json, statusCode: 200, data: [.get: MockedData.exampleJSON.data]).register()
162+
```
163+
164+
##### Ignoring URLs
165+
As the Mocker catches all URLs when registered, you might end up with a `fatalError` thrown in cases you don't need a mocked request. In that case you can ignore the URL:
166+
167+
```swift
168+
let ignoredURL = URL(string: "www.wetransfer.com")!
169+
Mocker.ignore(ignoredURL)
170+
```
171+
130172
## Communication
131173

132174
- If you **found a bug**, open an issue.

0 commit comments

Comments
 (0)