forked from mapbox/mapbox-directions-swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDirectionsTests.swift
223 lines (188 loc) · 9.31 KB
/
DirectionsTests.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import XCTest
#if !os(Linux)
import OHHTTPStubs
#if SWIFT_PACKAGE
import OHHTTPStubsSwift
#endif
#endif
#if canImport(CoreLocation)
import CoreLocation
#endif
import Turf
@testable import MapboxDirections
let BogusToken = "pk.feedCafeDadeDeadBeef-BadeBede.FadeCafeDadeDeed-BadeBede"
let BogusCredentials = Credentials(accessToken: BogusToken)
let BadResponse = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>413 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: RAf2XH13mMVxQ96Z1cVQMPrd-hJoVA6LfaWVFDbdN2j-J1VkzaPvZg==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
"""
#if !os(Linux)
class DirectionsTests: XCTestCase {
private let skuToken: String = "1234567890"
override func setUp() {
// Make sure tests run in all time zones
NSTimeZone.default = TimeZone(secondsFromGMT: 0)!
MBXAccounts.serviceSkuToken = skuToken
MBXAccounts.serviceAccessToken = BogusCredentials.accessToken
}
override func tearDown() {
HTTPStubs.removeAllStubs()
super.tearDown()
MBXAccounts.serviceSkuToken = nil
}
func testConfiguration() {
let directions = Directions(credentials: BogusCredentials)
XCTAssertEqual(directions.credentials, BogusCredentials)
}
let maximumCoordinateCount = 794
func testGETRequest() {
// Bumps right up against MaximumURLLength
let coordinates = Array(repeating: LocationCoordinate2D(latitude: 0, longitude: 0), count: maximumCoordinateCount)
let options = RouteOptions(coordinates: coordinates)
let directions = Directions(credentials: BogusCredentials)
let url = directions.url(forCalculating: options, httpMethod: "GET")
XCTAssertLessThanOrEqual(url.absoluteString.count, MaximumURLLength, "maximumCoordinateCount is too high")
guard let components = URLComponents(string: url.absoluteString),
let queryItems = components.queryItems else {
XCTFail("Invalid url"); return
}
XCTAssertEqual(queryItems.count, 8)
XCTAssertTrue(components.path.contains(coordinates.compactMap { $0.requestDescription }.joined(separator: ";")) )
XCTAssert(queryItems.contains(where: { $0.name == "sku" && $0.value == skuToken }) == true)
XCTAssert(queryItems.contains(where: { $0.name == "access_token" && $0.value == BogusToken }) == true)
let request = directions.urlRequest(forCalculating: options)
XCTAssertEqual(request.httpMethod, "GET")
XCTAssertEqual(request.url, url)
}
func testPOSTRequest() {
let coordinates = Array(repeating: LocationCoordinate2D(latitude: 0, longitude: 0), count: maximumCoordinateCount + 1)
let options = RouteOptions(coordinates: coordinates)
options.alleyPriority = .medium
let directions = Directions(credentials: BogusCredentials)
let request = directions.urlRequest(forCalculating: options)
XCTAssertEqual(request.httpMethod, "POST")
XCTAssertEqual(request.url?.query, "access_token=\(BogusToken)&sku=\(skuToken)")
XCTAssertNotNil(request.httpBody)
var components = URLComponents()
components.query = String(data: request.httpBody ?? Data(), encoding: .utf8)
XCTAssertEqual(components.queryItems?.count, 8)
XCTAssertEqual(components.queryItems?.first { $0.name == "coordinates" }?.value,
coordinates.compactMap { $0.requestDescription }.joined(separator: ";"))
}
func testKnownBadResponse() {
HTTPStubs.stubRequests(passingTest: { (request) -> Bool in
return request.url!.absoluteString.contains("https://api.mapbox.com/directions")
}) { (_) -> HTTPStubsResponse in
return HTTPStubsResponse(data: BadResponse.data(using: .utf8)!, statusCode: 413, headers: ["Content-Type" : "text/html"])
}
let expectation = self.expectation(description: "Async callback")
let one = CLLocation(latitude: 0.0, longitude: 0.0)
let two = CLLocation(latitude: 2.0, longitude: 2.0)
let directions = Directions(credentials: BogusCredentials)
let opts = RouteOptions(locations: [one, two])
directions.calculate(opts, completionHandler: { (session, result) in
guard case let .failure(error) = result else {
XCTFail("Expecting error, none returned.")
return
}
XCTAssertEqual(error, .requestTooLarge)
expectation.fulfill()
})
wait(for: [expectation], timeout: 2.0)
}
func testUnknownBadResponse() {
let message = "Enhance your calm, John Spartan."
HTTPStubs.stubRequests(passingTest: { (request) -> Bool in
return request.url!.absoluteString.contains("https://api.mapbox.com/directions")
}) { (_) -> HTTPStubsResponse in
return HTTPStubsResponse(data: message.data(using: .utf8)!, statusCode: 420, headers: ["Content-Type" : "text/plain"])
}
let expectation = self.expectation(description: "Async callback")
let one = CLLocation(latitude: 0.0, longitude: 0.0)
let two = CLLocation(latitude: 2.0, longitude: 2.0)
let directions = Directions(credentials: BogusCredentials)
let opts = RouteOptions(locations: [one, two])
directions.calculate(opts, completionHandler: { (session, result) in
defer { expectation.fulfill() }
guard case let .failure(error) = result else {
XCTFail("Expecting an error, none returned. \(result)")
return
}
guard case .invalidResponse(_) = error else {
XCTFail("Wrong error type returned.")
return
}
})
wait(for: [expectation], timeout: 2.0)
}
func testRateLimitErrorParsing() {
let url = URL(string: "https://api.mapbox.com")!
let headerFields = ["X-Rate-Limit-Interval" : "60", "X-Rate-Limit-Limit" : "600", "X-Rate-Limit-Reset" : "1479460584"]
let response = HTTPURLResponse(url: url, statusCode: 429, httpVersion: nil, headerFields: headerFields)
let resultError = DirectionsError(code: "429", message: "Hit rate limit", response: response, underlyingError: nil)
if case let .rateLimited(rateLimitInterval, rateLimit, resetTime) = resultError {
XCTAssertEqual(rateLimitInterval, 60.0)
XCTAssertEqual(rateLimit, 600)
XCTAssertEqual(resetTime, Date(timeIntervalSince1970: 1479460584))
} else {
XCTFail("Code 429 should be interpreted as a rate limiting error.")
}
}
func testDownNetwork() {
let notConnected = NSError(domain: NSURLErrorDomain, code: URLError.notConnectedToInternet.rawValue) as! URLError
HTTPStubs.stubRequests(passingTest: { (request) -> Bool in
return request.url!.absoluteString.contains("https://api.mapbox.com/directions")
}) { (_) -> HTTPStubsResponse in
return HTTPStubsResponse(error: notConnected)
}
let expectation = self.expectation(description: "Async callback")
let one = CLLocation(latitude: 0.0, longitude: 0.0)
let two = CLLocation(latitude: 2.0, longitude: 2.0)
let directions = Directions(credentials: BogusCredentials)
let opts = RouteOptions(locations: [one, two])
directions.calculate(opts, completionHandler: { (session, result) in
defer { expectation.fulfill() }
guard case let .failure(error) = result else {
XCTFail("Error expected, none returned. \(result)")
return
}
guard case let .network(err) = error else {
XCTFail("Wrong error type returned. \(error)")
return
}
// Comparing just the code and domain to avoid comparing unessential `UserInfo` that might be added.
XCTAssertEqual(type(of: err).errorDomain, type(of: notConnected).errorDomain)
XCTAssertEqual(err.code, notConnected.code)
})
wait(for: [expectation], timeout: 2.0)
}
func testRefreshRouteRequest() {
let directions = Directions(credentials: BogusCredentials)
guard let url = directions.urlRequest(forRefreshing: "any", routeIndex: 0, fromLegAtIndex: 0).url else {
XCTFail("Incorrect request"); return
}
XCTAssertLessThanOrEqual(url.absoluteString.count, MaximumURLLength, "maximumCoordinateCount is too high")
guard let queryItems = URLComponents(string: url.absoluteString)?.queryItems else {
XCTFail("Invalid url"); return
}
XCTAssertEqual(queryItems.count, 2)
XCTAssertTrue(queryItems.contains(where: { $0.name == "sku" && $0.value == skuToken }))
XCTAssertTrue(queryItems.contains(where: { $0.name == "access_token" && $0.value == BogusToken }))
}
}
#endif