summaryrefslogtreecommitdiff
path: root/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-02-11 12:21:49 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-02-12 14:53:52 -0800
commit13e2acbc754893efb945fe02d20824698415dcdb (patch)
treee8e4c966f03798fc6896a0fd3163e83921f84a38 /platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources
parentab677a7905b0f81850d6aa3dcdd2caebc0dbc851 (diff)
downloadqtlocation-mapboxgl-13e2acbc754893efb945fe02d20824698415dcdb.tar.gz
[ios, osx] Consolidate remaining files in platform/{ios,osx}
Diffstat (limited to 'platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources')
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h47
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h79
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m76
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h57
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m48
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h100
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m238
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m88
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m71
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h199
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m530
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h62
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m54
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h47
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m31
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h269
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m194
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h77
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m35
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h86
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m52
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift179
22 files changed, 2619 insertions, 0 deletions
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h
new file mode 100644
index 0000000000..b41ddda60f
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h
@@ -0,0 +1,47 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+/*
+ * This file allows to keep compatibility with older SDKs which didn't have
+ * the latest features and associated macros yet.
+ */
+
+
+#ifndef NS_DESIGNATED_INITIALIZER
+ #if __has_attribute(objc_designated_initializer)
+ #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
+ #else
+ #define NS_DESIGNATED_INITIALIZER
+ #endif
+#endif
+
+// Allow to use nullability macros and keywords even if not supported yet
+#if ! __has_feature(nullability)
+ #define NS_ASSUME_NONNULL_BEGIN
+ #define NS_ASSUME_NONNULL_END
+ #define nullable
+ #define __nullable
+ #define __nonnull
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h
new file mode 100644
index 0000000000..2776a4f3b7
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h
@@ -0,0 +1,79 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+/* This category is not available on watchOS because CFNetwork is needed for its implementation but isn't available on Nano */
+#if __has_include(<CFNetwork/CFNetwork.h>)
+
+#import <OHHTTPStubs/OHHTTPStubsResponse.h>
+#import <OHHTTPStubs/Compatibility.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Adds support for building stubs from "HTTP Messages" conforming to
+ * the format output by `curl -is`
+ *
+ * @note This category is not available on watchOS
+ */
+@interface OHHTTPStubsResponse (HTTPMessage)
+
+/*! @name Building a response from HTTP Message data */
+
+// TODO: Try to implement it using NSInputStream someday?
+
+/**
+ * Builds a response given a message data as returned by `curl -is [url]`, that is containing both the headers and the body.
+ *
+ * This method will split the headers and the body and build a OHHTTPStubsReponse accordingly
+ *
+ * @param responseData The NSData containing the whole HTTP response, including the headers and the body
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
++(instancetype)responseWithHTTPMessageData:(NSData*)responseData;
+
+/**
+ * Builds a response given the name of a `"*.response"` file containing both the headers and the body.
+ *
+ * The response file is expected to be in the specified bundle (or the application bundle if nil).
+ * This method will split the headers and the body and build a OHHTTPStubsReponse accordingly
+ *
+ * @param responseName The name of the `"*.response"` file (without extension) containing the whole
+ * HTTP response (including the headers and the body)
+ * @param bundleOrNil The bundle in which the `"*.response"` file is located. If `nil`, the
+ * `[NSBundle bundleForClass:self.class]` will be used.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
+
++(instancetype)responseNamed:(NSString*)responseName
+ inBundle:(nullable NSBundle*)bundleOrNil;
+
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m
new file mode 100644
index 0000000000..06d7363f23
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m
@@ -0,0 +1,76 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#if __has_include(<CFNetwork/CFNetwork.h>)
+#import <CFNetwork/CFNetwork.h>
+
+#import <OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h>
+
+@implementation OHHTTPStubsResponse (HTTPMessage)
+
+#pragma mark Building response from HTTP Message Data (dump from "curl -is")
+
++(instancetype)responseWithHTTPMessageData:(NSData*)responseData;
+{
+ NSData *data = [NSData data];
+ NSInteger statusCode = 200;
+ NSDictionary *headers = @{};
+
+ CFHTTPMessageRef httpMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE);
+ if (httpMessage)
+ {
+ CFHTTPMessageAppendBytes(httpMessage, responseData.bytes, responseData.length);
+
+ data = responseData; // By default
+
+ if (CFHTTPMessageIsHeaderComplete(httpMessage))
+ {
+ statusCode = (NSInteger)CFHTTPMessageGetResponseStatusCode(httpMessage);
+ headers = (__bridge_transfer NSDictionary *)CFHTTPMessageCopyAllHeaderFields(httpMessage);
+ data = (__bridge_transfer NSData *)CFHTTPMessageCopyBody(httpMessage);
+ }
+ CFRelease(httpMessage);
+ }
+
+ return [self responseWithData:data
+ statusCode:(int)statusCode
+ headers:headers];
+}
+
++(instancetype)responseNamed:(NSString*)responseName
+ inBundle:(nullable NSBundle*)responsesBundle
+{
+ NSURL *responseURL = [responsesBundle?:[NSBundle bundleForClass:self.class] URLForResource:responseName
+ withExtension:@"response"];
+
+ NSData *responseData = [NSData dataWithContentsOfURL:responseURL];
+ NSAssert(responseData, @"Could not find HTTP response named '%@' in bundle '%@'", responseName, responsesBundle);
+
+ return [self responseWithHTTPMessageData:responseData];
+}
+
+@end
+
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h
new file mode 100644
index 0000000000..3069ff32ec
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h
@@ -0,0 +1,57 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#import <OHHTTPStubs/OHHTTPStubsResponse.h>
+#import <OHHTTPStubs/Compatibility.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Adds convenience methods to manipulate JSON objects directly.
+ * Pass in an `NSDictionary` or `NSArray` to generate a corresponding JSON output.
+ */
+@interface OHHTTPStubsResponse (JSON)
+
+/**
+ * Builds a response given a JSON object for the response body, status code, and headers.
+ *
+ * @param jsonObject Object representing the response body.
+ * Typically a `NSDictionary`; may be any object accepted by `+[NSJSONSerialization dataWithJSONObject:options:error:]`
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ * If a "Content-Type" header is not included, "Content-Type: application/json" will be added.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note This method typically calls `responseWithData:statusCode:headers:`, passing the serialized JSON
+ * object as the data parameter and adding the Content-Type header if necessary.
+ */
++ (instancetype)responseWithJSONObject:(id)jsonObject
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary *)httpHeaders;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m
new file mode 100644
index 0000000000..d88fee9bdd
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m
@@ -0,0 +1,48 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#import <OHHTTPStubs/OHHTTPStubsResponse+JSON.h>
+
+@implementation OHHTTPStubsResponse (JSON)
+
+/*! @name Building a response from JSON objects */
+
++ (instancetype)responseWithJSONObject:(id)jsonObject
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary *)httpHeaders
+{
+ if (!httpHeaders[@"Content-Type"])
+ {
+ NSMutableDictionary* mutableHeaders = [NSMutableDictionary dictionaryWithDictionary:httpHeaders];
+ mutableHeaders[@"Content-Type"] = @"application/json";
+ httpHeaders = [NSDictionary dictionaryWithDictionary:mutableHeaders]; // make immutable again
+ }
+
+ return [self responseWithData:[NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:nil]
+ statusCode:statusCode
+ headers:httpHeaders];
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h
new file mode 100644
index 0000000000..77fe65e892
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h
@@ -0,0 +1,100 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2015 Jinlian (Sunny) Wang
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+#import <OHHTTPStubs/OHHTTPStubs.h>
+#import <OHHTTPStubs/Compatibility.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Error codes for the OHHTTPStubs Mocktail category
+ */
+typedef NS_ENUM(NSInteger, OHHTTPStubsMocktailError) {
+ /** The specified path does not exist */
+ OHHTTPStubsMocktailErrorPathDoesNotExist = 1,
+ /** The specified path was not readable */
+ OHHTTPStubsMocktailErrorPathFailedToRead,
+ /** The specified path is not a directory */
+ OHHTTPStubsMocktailErrorPathIsNotFolder,
+ /** The specified file is not a valid Mocktail file */
+ OHHTTPStubsMocktailErrorInvalidFileFormat,
+ /** The specified Mocktail file has invalid headers */
+ OHHTTPStubsMocktailErrorInvalidFileHeader,
+ /** An unexpected internal error occured */
+ OHHTTPStubsMocktailErrorInternalError
+};
+
+extern NSString* const MocktailErrorDomain;
+
+@interface OHHTTPStubs (Mocktail)
+
+/**
+ * Add a stub given a file in the format of Mocktail as defined at https://github.com/square/objc-mocktail.
+ *
+ * This method will split the HTTP method Regex, the absolute URL Regex, the headers, the HTTP status code and
+ * response body, and use them to add a stub.
+ *
+ * @param fileName The name of the mocktail file (without extension of '.tail') in the Mocktail format.
+ * @param bundleOrNil The bundle in which the mocktail file is located. If `nil`, the `[NSBundle bundleForClass:self.class]` will be used.
+ * @param error An out value that returns any error encountered during stubbing. Returns an NSError object if any error; otherwise returns nil.
+ *
+ * @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with
+ * `removeStub:`.
+ */
++(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error;
+
+/**
+ * Add a stub given a file URL in the format of Mocktail as defined at https://github.com/square/objc-mocktail.
+ *
+ * This method will split the HTTP method Regex, the absolute URL Regex, the headers, the HTTP status code and
+ * response body, and use them to add a stub.
+ *
+ * @param fileURL The URL pointing to the file in the Mocktail format.
+ * @param error An out value that returns any error encountered during stubbing. Returns an NSError object if any error; otherwise returns nil.
+ *
+ * @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with
+ * `removeStub:`.
+ */
++(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL error:(NSError **)error;
+
+/**
+ * Add stubs using files under a folder in the format of Mocktail as defined at https://github.com/square/objc-mocktail.
+ *
+ * This method will retrieve all the files under the folder; for each file with surfix of ".tail", it will split the HTTP method Regex, the absolute URL Regex, the headers, the HTTP status code and response body, and use them to add a stub.
+ *
+ * @param path The name of the folder containing files in the Mocktail format.
+ * @param bundleOrNil The bundle in which the path is located. If `nil`, the `[NSBundle bundleForClass:self.class]` will be used.
+ * @param error An out value that returns any error encountered during stubbing. Returns an NSError object if any error; otherwise returns nil.
+ *
+ * @return an array of stub descriptor that uniquely identifies the stub and can be later used to remove it with
+ * `removeStub:`.
+ */
++(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m
new file mode 100644
index 0000000000..4de8996ae0
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m
@@ -0,0 +1,238 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2015 Jinlian (Sunny) Wang
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+#import <OHHTTPStubs/OHHTTPStubs+Mocktail.h>
+
+NSString* const MocktailErrorDomain = @"Mocktail";
+
+@implementation OHHTTPStubs (Mocktail)
+
+
++(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error
+{
+ NSURL *dirURL = [bundleOrNil?:[NSBundle bundleForClass:self.class] URLForResource:path withExtension:nil];
+ if (!dirURL)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorPathDoesNotExist userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Path '%@' does not exist.", path]}];
+ }
+ return nil;
+ }
+
+ // Make sure path points to a directory
+ NSNumber *isDirectory;
+ BOOL success = [dirURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];
+ BOOL isDir = (success && [isDirectory boolValue]);
+
+ if (!isDir)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorPathIsNotFolder userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Path '%@' is not a folder.", path]}];
+ }
+ return nil;
+ }
+
+ // Read the content of the directory
+ NSError *bError = nil;
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSArray *fileURLs = [fileManager contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:nil options:0 error:&bError];
+
+ if (bError)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorPathFailedToRead userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Error reading path '%@'.", dirURL.absoluteString]}];
+ }
+ return nil;
+ }
+
+ //stub the Mocktail-formatted requests
+ NSMutableArray *descriptorArray = [[NSMutableArray alloc] initWithCapacity:fileURLs.count];
+ for (NSURL *fileURL in fileURLs)
+ {
+ if (![fileURL.absoluteString hasSuffix:@".tail"])
+ {
+ continue;
+ }
+ id<OHHTTPStubsDescriptor> descriptor = [[self class] stubRequestsUsingMocktail:fileURL error: &bError];
+ if (descriptor && !bError)
+ {
+ [descriptorArray addObject:descriptor];
+ }
+ }
+
+ return descriptorArray;
+}
+
++(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error
+{
+ NSURL *responseURL = [bundleOrNil?:[NSBundle bundleForClass:self.class] URLForResource:fileName withExtension:@"tail"];
+
+ if (!responseURL)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorPathDoesNotExist userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' does not exist.", fileName]}];
+ }
+ return nil;
+ }
+ else
+ {
+ return [[self class] stubRequestsUsingMocktail:responseURL error:error];
+ }
+}
+
++(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL error:(NSError **)error
+{
+ NSError *bError = nil;
+ NSStringEncoding originalEncoding;
+ NSString *contentsOfFile = [NSString stringWithContentsOfURL:fileURL usedEncoding:&originalEncoding error:&bError];
+
+ if (!contentsOfFile || bError)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorPathFailedToRead userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' does not read.", fileURL.absoluteString]}];
+ }
+ return nil;
+ }
+
+ NSScanner *scanner = [NSScanner scannerWithString:contentsOfFile];
+ NSString *headerMatter = nil;
+ [scanner scanUpToString:@"\n\n" intoString:&headerMatter];
+ NSArray *lines = [headerMatter componentsSeparatedByString:@"\n"];
+ if (lines.count < 4)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorInvalidFileFormat userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' has invalid amount of lines:%u.", fileURL.absoluteString, (unsigned)lines.count]}];
+ }
+ return nil;
+ }
+
+ /* Handle Mocktail format, adapted from Mocktail implementation
+ For more details on the file format, check out: https://github.com/square/objc-Mocktail */
+ NSRegularExpression *methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:&bError];
+
+ if (bError)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorInvalidFileFormat userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' has invalid method regular expression pattern: %@.", fileURL.absoluteString, lines[0]]}];
+ }
+ return nil;
+ }
+
+ NSRegularExpression *absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:&bError];
+
+ if (bError)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorInvalidFileFormat userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' has invalid URL regular expression pattern: %@.", fileURL.absoluteString, lines[1]]}];
+ }
+ return nil;
+ }
+
+ NSInteger statusCode = [lines[2] integerValue];
+
+ NSMutableDictionary *headers = @{@"Content-Type":lines[3]}.mutableCopy;
+
+ // From line 5 to '\n\n', expect HTTP response headers.
+ NSRegularExpression *headerPattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+):\\s+(.*)" options:0 error:&bError];
+ if (bError)
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorInternalError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Internal error while stubbing file '%@'.", fileURL.absoluteString]}];
+ }
+ return nil;
+ }
+
+ for (NSUInteger line = 4; line < lines.count; line ++) {
+ NSString *headerLine = lines[line];
+ NSTextCheckingResult *match = [headerPattern firstMatchInString:headerLine options:0 range:NSMakeRange(0, headerLine.length)];
+
+ if (match)
+ {
+ NSString *key = [headerLine substringWithRange:[match rangeAtIndex:1]];
+ NSString *value = [headerLine substringWithRange:[match rangeAtIndex:2]];
+ headers[key] = value;
+ }
+ else
+ {
+ if (error)
+ {
+ *error = [NSError errorWithDomain:MocktailErrorDomain code:OHHTTPStubsMocktailErrorInvalidFileHeader userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File '%@' has invalid header: %@.", fileURL.absoluteString, headerLine]}];
+ }
+ return nil;
+ }
+ }
+
+ // Handle binary which is base64 encoded
+ NSUInteger bodyOffset = [headerMatter dataUsingEncoding:NSUTF8StringEncoding].length + 2;
+
+ return [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
+ NSString *absoluteURL = (request.URL).absoluteString;
+ NSString *method = request.HTTPMethod;
+
+ if ([absoluteURLRegex numberOfMatchesInString:absoluteURL options:0 range:NSMakeRange(0, absoluteURL.length)] > 0)
+ {
+ if ([methodRegex numberOfMatchesInString:method options:0 range:NSMakeRange(0, method.length)] > 0)
+ {
+ return YES;
+ }
+ }
+
+ return NO;
+ } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
+ if([headers[@"Content-Type"] hasSuffix:@";base64"])
+ {
+ NSString *type = headers[@"Content-Type"];
+ NSString *newType = [type substringWithRange:NSMakeRange(0, type.length - 7)];
+ headers[@"Content-Type"] = newType;
+
+ NSData *body = [NSData dataWithContentsOfURL:fileURL];
+ body = [body subdataWithRange:NSMakeRange(bodyOffset, body.length - bodyOffset)];
+ body = [[NSData alloc] initWithBase64EncodedData:body options:NSDataBase64DecodingIgnoreUnknownCharacters];
+
+ OHHTTPStubsResponse *response = [OHHTTPStubsResponse responseWithData:body statusCode:(int)statusCode headers:headers];
+ return response;
+ }
+ else
+ {
+ OHHTTPStubsResponse *response = [OHHTTPStubsResponse responseWithFileAtPath:fileURL.path
+ statusCode:(int)statusCode headers:headers];
+ [response.inputStream setProperty:@(bodyOffset) forKey:NSStreamFileCurrentOffsetKey];
+ return response;
+ }
+ }];
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m
new file mode 100644
index 0000000000..b0e14a093c
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m
@@ -0,0 +1,88 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#import <Foundation/Foundation.h>
+
+#if defined(__IPHONE_7_0) || defined(__MAC_10_9)
+
+#import <objc/runtime.h>
+#import <OHHTTPStubs/OHHTTPStubs.h>
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This helper is used to swizzle NSURLSessionConfiguration constructor methods
+ * defaultSessionConfiguration and ephemeralSessionConfiguration to insert the private
+ * OHHTTPStubsProtocol into their protocolClasses array so that OHHTTPStubs is automagically
+ * supported when you create a new NSURLSession based on one of there configurations.
+ */
+
+typedef NSURLSessionConfiguration*(*SessionConfigConstructor)(id,SEL);
+static SessionConfigConstructor orig_defaultSessionConfiguration;
+static SessionConfigConstructor orig_ephemeralSessionConfiguration;
+
+static SessionConfigConstructor OHHTTPStubsSwizzle(SEL selector, SessionConfigConstructor newImpl)
+{
+ Class cls = NSURLSessionConfiguration.class;
+ Class metaClass = object_getClass(cls);
+
+ Method origMethod = class_getClassMethod(cls, selector);
+ SessionConfigConstructor origImpl = (SessionConfigConstructor)method_getImplementation(origMethod);
+ if (!class_addMethod(metaClass, selector, (IMP)newImpl, method_getTypeEncoding(origMethod)))
+ {
+ method_setImplementation(origMethod, (IMP)newImpl);
+ }
+ return origImpl;
+}
+
+static NSURLSessionConfiguration* OHHTTPStubs_defaultSessionConfiguration(id self, SEL _cmd)
+{
+ NSURLSessionConfiguration* config = orig_defaultSessionConfiguration(self,_cmd); // call original method
+ [OHHTTPStubs setEnabled:YES forSessionConfiguration:config]; //OHHTTPStubsAddProtocolClassToNSURLSessionConfiguration(config);
+ return config;
+}
+
+static NSURLSessionConfiguration* OHHTTPStubs_ephemeralSessionConfiguration(id self, SEL _cmd)
+{
+ NSURLSessionConfiguration* config = orig_ephemeralSessionConfiguration(self,_cmd); // call original method
+ [OHHTTPStubs setEnabled:YES forSessionConfiguration:config]; //OHHTTPStubsAddProtocolClassToNSURLSessionConfiguration(config);
+ return config;
+}
+
+@interface NSURLSessionConfiguration(OHHTTPStubsSupport) @end
+@implementation NSURLSessionConfiguration(OHHTTPStubsSupport)
++(void)load
+{
+ orig_defaultSessionConfiguration = OHHTTPStubsSwizzle(@selector(defaultSessionConfiguration),
+ OHHTTPStubs_defaultSessionConfiguration);
+ orig_ephemeralSessionConfiguration = OHHTTPStubsSwizzle(@selector(ephemeralSessionConfiguration),
+ OHHTTPStubs_ephemeralSessionConfiguration);
+}
+@end
+
+#endif
+
+
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m
new file mode 100644
index 0000000000..1184dcad1f
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m
@@ -0,0 +1,71 @@
+//
+// NSURLSessionConfiguration+OHHTTPStubs.m
+// OHHTTPStubs
+//
+// Created by Olivier Halligon on 06/10/13.
+// Copyright (c) 2013 AliSoftware. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#if defined(__IPHONE_7_0) || defined(__MAC_10_9)
+
+#import <objc/runtime.h>
+#import "OHHTTPStubs.h"
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This helper is used to swizzle NSURLSessionConfiguration constructor methods
+ * defaultSessionConfiguration and ephemeralSessionConfiguration to insert the private
+ * OHHTTPStubsProtocol into their protocolClasses array so that OHHTTPStubs is automagically
+ * supported when you create a new NSURLSession based on one of there configurations.
+ */
+
+typedef NSURLSessionConfiguration*(*SessionConfigConstructor)(id,SEL);
+static SessionConfigConstructor orig_defaultSessionConfiguration;
+static SessionConfigConstructor orig_ephemeralSessionConfiguration;
+
+static SessionConfigConstructor OHHTTPStubsSwizzle(SEL selector, SessionConfigConstructor newImpl)
+{
+ Class cls = NSURLSessionConfiguration.class;
+ Class metaClass = object_getClass(cls);
+
+ Method origMethod = class_getClassMethod(cls, selector);
+ SessionConfigConstructor origImpl = (SessionConfigConstructor)method_getImplementation(origMethod);
+ if (!class_addMethod(metaClass, selector, (IMP)newImpl, method_getTypeEncoding(origMethod)))
+ {
+ method_setImplementation(origMethod, (IMP)newImpl);
+ }
+ return origImpl;
+}
+
+static NSURLSessionConfiguration* OHHTTPStubs_defaultSessionConfiguration(id self, SEL _cmd)
+{
+ NSURLSessionConfiguration* config = orig_defaultSessionConfiguration(self,_cmd); // call original method
+ [OHHTTPStubs setEnabled:YES forSessionConfiguration:config]; //OHHTTPStubsAddProtocolClassToNSURLSessionConfiguration(config);
+ return config;
+}
+
+static NSURLSessionConfiguration* OHHTTPStubs_ephemeralSessionConfiguration(id self, SEL _cmd)
+{
+ NSURLSessionConfiguration* config = orig_ephemeralSessionConfiguration(self,_cmd); // call original method
+ [OHHTTPStubs setEnabled:YES forSessionConfiguration:config]; //OHHTTPStubsAddProtocolClassToNSURLSessionConfiguration(config);
+ return config;
+}
+
+@interface NSURLSessionConfiguration(OHHTTPStubsSupport) @end
+@implementation NSURLSessionConfiguration(OHHTTPStubsSupport)
++(void)load
+{
+ orig_defaultSessionConfiguration = OHHTTPStubsSwizzle(@selector(defaultSessionConfiguration),
+ OHHTTPStubs_defaultSessionConfiguration);
+ orig_ephemeralSessionConfiguration = OHHTTPStubsSwizzle(@selector(ephemeralSessionConfiguration),
+ OHHTTPStubs_ephemeralSessionConfiguration);
+}
+@end
+
+#endif
+
+
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h
new file mode 100644
index 0000000000..f4c2a07a98
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h
@@ -0,0 +1,199 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Imports
+
+#import <Foundation/Foundation.h>
+
+#import "Compatibility.h"
+#import "OHHTTPStubsResponse.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Types
+
+typedef BOOL(^OHHTTPStubsTestBlock)(NSURLRequest* request);
+typedef OHHTTPStubsResponse* __nonnull (^OHHTTPStubsResponseBlock)( NSURLRequest* request);
+
+/**
+ * This opaque type represents an installed stub and is used to uniquely
+ * identify a stub once it has been created.
+ *
+ * This type is returned by the `stubRequestsPassingTest:withStubResponse:` method
+ * so that you can later reference it and use this reference to remove the stub later.
+ *
+ * This type also let you add arbitrary metadata to a stub to differenciate it
+ * more easily when debugging.
+ */
+@protocol OHHTTPStubsDescriptor <NSObject>
+/**
+ * An arbitrary name that you can set and get to describe your stub.
+ * Use it as your own convenience.
+ *
+ * This is especially useful if you dump all installed stubs using `allStubs`
+ * or if you want to log which stubs are being triggered using `onStubActivation:`.
+ */
+@property(nonatomic, strong, nullable) NSString* name;
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Interface
+
+/**
+ * Stubs Manager. Use this class to add and remove stubs and stub your network requests.
+ */
+@interface OHHTTPStubs : NSObject
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Adding & Removing stubs
+
+
+
+/**
+ * Dedicated method to add a stub
+ *
+ * @param testBlock Block that should return `YES` if the request passed as parameter
+ * should be stubbed with the response block, and `NO` if it should
+ * hit the real world (or be managed by another stub).
+ * @param responseBlock Block that will return the `OHHTTPStubsResponse` (response to
+ * use for stubbing) corresponding to the given request
+ *
+ * @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with `removeStub:`.
+ *
+ * @note The returned stub descriptor is retained (`__strong` reference) by `OHHTTPStubs`
+ * until it is removed (with one of the `removeStub:` / `removeAllStubs`
+ * methods); it is thus recommended to keep it in a `__weak` storage (and not `__strong`)
+ * in your app code, to let the stub descriptor be destroyed and let the variable go
+ * back to `nil` automatically when the stub is removed.
+ */
++(id<OHHTTPStubsDescriptor>)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
+ withStubResponse:(OHHTTPStubsResponseBlock)responseBlock;
+
+/**
+ * Remove a stub from the list of stubs
+ *
+ * @param stubDesc The stub descriptor that has been returned when adding the stub
+ * using `stubRequestsPassingTest:withStubResponse:`
+ *
+ * @return `YES` if the stub has been successfully removed, `NO` if the parameter was
+ * not a valid stub identifier
+ */
++(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc;
+
+/**
+ * Remove all the stubs from the stubs list.
+ */
++(void)removeAllStubs;
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Disabling & Re-Enabling stubs
+
+/**
+ * Enable or disable the stubs for the shared session or for `NSURLConnection`
+ *
+ * @param enabled If `YES`, enables the stubs. If `NO`, disable all the
+ * stubs and let all the requests hit the real world.
+ *
+ * @note OHHTTPStubs are enabled by default, so there is no need to call
+ * this method with `YES` for stubs to work, except if you explicitely
+ * disabled the stubs before.
+ *
+ * @note This only affects requests that are further made using `NSURLConnection`
+ * or using `[NSURLSession sharedSession]`. This does not affect requests
+ * sent on an `NSURLSession` created using an `NSURLSessionConfiguration`.
+ */
++(void)setEnabled:(BOOL)enabled;
+
+#if defined(__IPHONE_7_0) || defined(__MAC_10_9)
+/**
+ * Enable or disable the stubs on a given `NSURLSessionConfiguration`.
+ *
+ * @param enabled If `YES`, enables the stubs for this `NSURLSessionConfiguration`.
+ * If `NO`, disable the stubs and let all the requests hit the real world
+ * @param sessionConfig The NSURLSessionConfiguration on which to enabled/disable the stubs
+ *
+ * @note OHHTTPStubs are enabled by default on newly created `defaultSessionConfiguration`
+ * and `ephemeralSessionConfiguration`, so there is no need to call this method with
+ * `YES` for stubs to work. You generally only use this if you want to disable
+ * `OHTTPStubs` per `NSURLSession` by calling it before building the `NSURLSession`
+ * with the `NSURLSessionConfiguration`.
+ *
+ * @note Important: As usual according to the way `NSURLSessionConfiguration` works, you
+ * MUST set this property BEFORE creating the `NSURLSession`. Once the `NSURLSession`
+ * object is created, they use a deep copy of the `NSURLSessionConfiguration` object
+ * used to create them, so changing the configuration later does not affect already
+ * created sessions.
+ */
++ (void)setEnabled:(BOOL)enabled forSessionConfiguration:(NSURLSessionConfiguration *)sessionConfig;
+#endif
+
+#pragma mark - Debug Methods
+
+/**
+ * List all the installed stubs
+ *
+ * @return An array of `id<OHHTTPStubsDescriptor>` objects currently installed. Useful for debug.
+ */
++(NSArray*)allStubs;
+
+/**
+ * Setup a block to be called each time a stub is triggered.
+ *
+ * Useful if you want to log all your requests being stubbed for example and see which stub
+ * was used to respond to each request.
+ *
+ * @param block The block to call each time a request is being stubbed by OHHTTPStubs.
+ * Set it to `nil` to do nothing. Defaults is `nil`.
+ */
++(void)onStubActivation:( void(^)(NSURLRequest* request, id<OHHTTPStubsDescriptor> stub) )block;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Umbrella Header Imports
+
+
+#if ! __has_include("OHHTTPStubs/OHHTTPStubs-umbrella.h")
+ // Because this is supposed to be an umbrella header, we should also import every public headers here
+ // (Except if we use already have a better umbrella header generated by CocoaPods)
+ #if __has_include("OHHTTPStubs/OHHTTPStubsResponse+JSON.h")
+ #import "OHHTTPStubs/OHHTTPStubsResponse+JSON.h"
+ #endif
+ #if __has_include("OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h")
+ #import "OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h"
+ #endif
+ #if __has_include("OHHTTPStubs/OHHTTPStubs+Mocktail.h")
+ #import "OHHTTPStubs/OHHTTPStubs+Mocktail.h"
+ #endif
+ #if __has_include("OHHTTPStubs/OHPathHelpers.h")
+ #import "OHHTTPStubs/OHPathHelpers.h"
+ #endif
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m
new file mode 100644
index 0000000000..4fa31f907b
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m
@@ -0,0 +1,530 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+#if ! __has_feature(objc_arc)
+#error This file is expected to be compiled with ARC turned ON
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Imports
+
+#import "OHHTTPStubs.h"
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Types & Constants
+
+@interface OHHTTPStubsProtocol : NSURLProtocol @end
+
+static NSTimeInterval const kSlotTime = 0.25; // Must be >0. We will send a chunk of the data from the stream each 'slotTime' seconds
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Private Interfaces
+
+@interface OHHTTPStubs()
++ (instancetype)sharedInstance;
+@property(atomic, copy) NSMutableArray* stubDescriptors;
+@property(atomic, copy) void (^onStubActivationBlock)(NSURLRequest*, id<OHHTTPStubsDescriptor>);
+@end
+
+@interface OHHTTPStubsDescriptor : NSObject <OHHTTPStubsDescriptor>
+@property(atomic, copy) OHHTTPStubsTestBlock testBlock;
+@property(atomic, copy) OHHTTPStubsResponseBlock responseBlock;
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - OHHTTPStubsDescriptor Implementation
+
+@implementation OHHTTPStubsDescriptor
+
+@synthesize name = _name;
+
++(instancetype)stubDescriptorWithTestBlock:(OHHTTPStubsTestBlock)testBlock
+ responseBlock:(OHHTTPStubsResponseBlock)responseBlock
+{
+ OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor new];
+ stub.testBlock = testBlock;
+ stub.responseBlock = responseBlock;
+ return stub;
+}
+
+-(NSString*)description
+{
+ return [NSString stringWithFormat:@"<%@ %p : %@>", self.class, self, self.name];
+}
+
+@end
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - OHHTTPStubs Implementation
+
+@implementation OHHTTPStubs
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Singleton methods
+
++ (instancetype)sharedInstance
+{
+ static OHHTTPStubs *sharedInstance = nil;
+
+ static dispatch_once_t predicate;
+ dispatch_once(&predicate, ^{
+ sharedInstance = [[self alloc] init];
+ });
+
+ return sharedInstance;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Setup & Teardown
+
++ (void)initialize
+{
+ if (self == [OHHTTPStubs class])
+ {
+ [self setEnabled:YES];
+ }
+}
+- (instancetype)init
+{
+ self = [super init];
+ if (self)
+ {
+ _stubDescriptors = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [self.class setEnabled:NO];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Public class methods
+
+#pragma mark > Adding & Removing stubs
+
++(id<OHHTTPStubsDescriptor>)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
+ withStubResponse:(OHHTTPStubsResponseBlock)responseBlock
+{
+ OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor stubDescriptorWithTestBlock:testBlock
+ responseBlock:responseBlock];
+ [OHHTTPStubs.sharedInstance addStub:stub];
+ return stub;
+}
+
++(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc
+{
+ return [OHHTTPStubs.sharedInstance removeStub:stubDesc];
+}
+
++(void)removeAllStubs
+{
+ [OHHTTPStubs.sharedInstance removeAllStubs];
+}
+
+#pragma mark > Disabling & Re-Enabling stubs
+
++(void)setEnabled:(BOOL)enable
+{
+ static BOOL currentEnabledState = NO;
+ if (enable && !currentEnabledState)
+ {
+ [NSURLProtocol registerClass:OHHTTPStubsProtocol.class];
+ }
+ else if (!enable && currentEnabledState)
+ {
+ [NSURLProtocol unregisterClass:OHHTTPStubsProtocol.class];
+ }
+ currentEnabledState = enable;
+}
+
+#if defined(__IPHONE_7_0) || defined(__MAC_10_9)
++ (void)setEnabled:(BOOL)enable forSessionConfiguration:(NSURLSessionConfiguration*)sessionConfig
+{
+ // Runtime check to make sure the API is available on this version
+ if ( [sessionConfig respondsToSelector:@selector(protocolClasses)]
+ && [sessionConfig respondsToSelector:@selector(setProtocolClasses:)])
+ {
+ NSMutableArray * urlProtocolClasses = [NSMutableArray arrayWithArray:sessionConfig.protocolClasses];
+ Class protoCls = OHHTTPStubsProtocol.class;
+ if (enable && ![urlProtocolClasses containsObject:protoCls])
+ {
+ [urlProtocolClasses insertObject:protoCls atIndex:0];
+ }
+ else if (!enable && [urlProtocolClasses containsObject:protoCls])
+ {
+ [urlProtocolClasses removeObject:protoCls];
+ }
+ sessionConfig.protocolClasses = urlProtocolClasses;
+ }
+ else
+ {
+ NSLog(@"[OHHTTPStubs] %@ is only available when running on iOS7+/OSX9+. "
+ @"Use conditions like 'if ([NSURLSessionConfiguration class])' to only call "
+ @"this method if the user is running iOS7+/OSX9+.", NSStringFromSelector(_cmd));
+ }
+}
+#endif
+
+#pragma mark > Debug Methods
+
++(NSArray*)allStubs
+{
+ return [OHHTTPStubs.sharedInstance stubDescriptors];
+}
+
++(void)onStubActivation:( void(^)(NSURLRequest* request, id<OHHTTPStubsDescriptor> stub) )block
+{
+ [OHHTTPStubs.sharedInstance setOnStubActivationBlock:block];
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Private instance methods
+
+-(void)addStub:(OHHTTPStubsDescriptor*)stubDesc
+{
+ @synchronized(_stubDescriptors)
+ {
+ [_stubDescriptors addObject:stubDesc];
+ }
+}
+
+-(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc
+{
+ BOOL handlerFound = NO;
+ @synchronized(_stubDescriptors)
+ {
+ handlerFound = [_stubDescriptors containsObject:stubDesc];
+ [_stubDescriptors removeObject:stubDesc];
+ }
+ return handlerFound;
+}
+
+-(void)removeAllStubs
+{
+ @synchronized(_stubDescriptors)
+ {
+ [_stubDescriptors removeAllObjects];
+ }
+}
+
+- (OHHTTPStubsDescriptor*)firstStubPassingTestForRequest:(NSURLRequest*)request
+{
+ OHHTTPStubsDescriptor* foundStub = nil;
+ @synchronized(_stubDescriptors)
+ {
+ for(OHHTTPStubsDescriptor* stub in _stubDescriptors.reverseObjectEnumerator)
+ {
+ if (stub.testBlock(request))
+ {
+ foundStub = stub;
+ break;
+ }
+ }
+ }
+ return foundStub;
+}
+
+@end
+
+
+
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Private Protocol Class
+
+@interface OHHTTPStubsProtocol()
+@property(assign) BOOL stopped;
+@property(strong) OHHTTPStubsDescriptor* stub;
+@property(assign) CFRunLoopRef clientRunLoop;
+- (void)executeOnClientRunLoopAfterDelay:(NSTimeInterval)delayInSeconds block:(dispatch_block_t)block;
+@end
+
+@implementation OHHTTPStubsProtocol
+
++ (BOOL)canInitWithRequest:(NSURLRequest *)request
+{
+ return ([OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request] != nil);
+}
+
+- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)response client:(id<NSURLProtocolClient>)client
+{
+ // Make super sure that we never use a cached response.
+ OHHTTPStubsProtocol* proto = [super initWithRequest:request cachedResponse:nil client:client];
+ proto.stub = [OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request];
+ return proto;
+}
+
++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
+{
+ return request;
+}
+
+- (NSCachedURLResponse *)cachedResponse
+{
+ return nil;
+}
+
+- (void)startLoading
+{
+ self.clientRunLoop = CFRunLoopGetCurrent();
+ NSURLRequest* request = self.request;
+ id<NSURLProtocolClient> client = self.client;
+
+ if (!self.stub)
+ {
+ NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"It seems like the stub has been removed BEFORE the response had time to be sent.",
+ NSLocalizedFailureReasonErrorKey,
+ @"For more info, see https://github.com/AliSoftware/OHHTTPStubs/wiki/OHHTTPStubs-and-asynchronous-tests",
+ NSLocalizedRecoverySuggestionErrorKey,
+ request.URL, // Stop right here if request.URL is nil
+ NSURLErrorFailingURLErrorKey,
+ nil];
+ NSError* error = [NSError errorWithDomain:@"OHHTTPStubs" code:500 userInfo:userInfo];
+ [client URLProtocol:self didFailWithError:error];
+ return;
+ }
+
+ OHHTTPStubsResponse* responseStub = self.stub.responseBlock(request);
+
+ if (OHHTTPStubs.sharedInstance.onStubActivationBlock)
+ {
+ OHHTTPStubs.sharedInstance.onStubActivationBlock(request, self.stub);
+ }
+
+ if (responseStub.error == nil)
+ {
+ NSHTTPURLResponse* urlResponse = [[NSHTTPURLResponse alloc] initWithURL:request.URL
+ statusCode:responseStub.statusCode
+ HTTPVersion:@"HTTP/1.1"
+ headerFields:responseStub.httpHeaders];
+
+ // Cookies handling
+ if (request.HTTPShouldHandleCookies && request.URL)
+ {
+ NSArray* cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseStub.httpHeaders forURL:request.URL];
+ if (cookies)
+ {
+ [NSHTTPCookieStorage.sharedHTTPCookieStorage setCookies:cookies forURL:request.URL mainDocumentURL:request.mainDocumentURL];
+ }
+ }
+
+
+ NSString* redirectLocation = (responseStub.httpHeaders)[@"Location"];
+ NSURL* redirectLocationURL;
+ if (redirectLocation)
+ {
+ redirectLocationURL = [NSURL URLWithString:redirectLocation];
+ }
+ else
+ {
+ redirectLocationURL = nil;
+ }
+ if (((responseStub.statusCode > 300) && (responseStub.statusCode < 400)) && redirectLocationURL)
+ {
+ NSURLRequest* redirectRequest = [NSURLRequest requestWithURL:redirectLocationURL];
+ [self executeOnClientRunLoopAfterDelay:responseStub.requestTime block:^{
+ if (!self.stopped)
+ {
+ [client URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:urlResponse];
+ }
+ }];
+ }
+ else
+ {
+ [self executeOnClientRunLoopAfterDelay:responseStub.requestTime block:^{
+ if (!self.stopped)
+ {
+ [client URLProtocol:self didReceiveResponse:urlResponse cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ if(responseStub.inputStream.streamStatus == NSStreamStatusNotOpen)
+ {
+ [responseStub.inputStream open];
+ }
+ [self streamDataForClient:client
+ withStubResponse:responseStub
+ completion:^(NSError * error)
+ {
+ [responseStub.inputStream close];
+ if (error==nil)
+ {
+ [client URLProtocolDidFinishLoading:self];
+ }
+ else
+ {
+ [client URLProtocol:self didFailWithError:responseStub.error];
+ }
+ }];
+ }
+ }];
+ }
+ } else {
+ // Send the canned error
+ [self executeOnClientRunLoopAfterDelay:responseStub.responseTime block:^{
+ if (!self.stopped)
+ {
+ [client URLProtocol:self didFailWithError:responseStub.error];
+ }
+ }];
+ }
+}
+
+- (void)stopLoading
+{
+ self.stopped = YES;
+}
+
+typedef struct {
+ NSTimeInterval slotTime;
+ double chunkSizePerSlot;
+ double cumulativeChunkSize;
+} OHHTTPStubsStreamTimingInfo;
+
+- (void)streamDataForClient:(id<NSURLProtocolClient>)client
+ withStubResponse:(OHHTTPStubsResponse*)stubResponse
+ completion:(void(^)(NSError * error))completion
+{
+ if ((stubResponse.dataSize>0) && stubResponse.inputStream.hasBytesAvailable && (!self.stopped))
+ {
+ // Compute timing data once and for all for this stub
+
+ OHHTTPStubsStreamTimingInfo timingInfo = {
+ .slotTime = kSlotTime, // Must be >0. We will send a chunk of data from the stream each 'slotTime' seconds
+ .cumulativeChunkSize = 0
+ };
+
+ if(stubResponse.responseTime < 0)
+ {
+ // Bytes send each 'slotTime' seconds = Speed in KB/s * 1000 * slotTime in seconds
+ timingInfo.chunkSizePerSlot = (fabs(stubResponse.responseTime) * 1000) * timingInfo.slotTime;
+ }
+ else if (stubResponse.responseTime < kSlotTime) // includes case when responseTime == 0
+ {
+ // We want to send the whole data quicker than the slotTime, so send it all in one chunk.
+ timingInfo.chunkSizePerSlot = stubResponse.dataSize;
+ timingInfo.slotTime = stubResponse.responseTime;
+ }
+ else
+ {
+ // Bytes send each 'slotTime' seconds = (Whole size in bytes / response time) * slotTime = speed in bps * slotTime in seconds
+ timingInfo.chunkSizePerSlot = ((stubResponse.dataSize/stubResponse.responseTime) * timingInfo.slotTime);
+ }
+
+ [self streamDataForClient:client
+ fromStream:stubResponse.inputStream
+ timingInfo:timingInfo
+ completion:completion];
+ }
+ else
+ {
+ if (completion)
+ {
+ completion(nil);
+ }
+ }
+}
+
+- (void) streamDataForClient:(id<NSURLProtocolClient>)client
+ fromStream:(NSInputStream*)inputStream
+ timingInfo:(OHHTTPStubsStreamTimingInfo)timingInfo
+ completion:(void(^)(NSError * error))completion
+{
+ NSParameterAssert(timingInfo.chunkSizePerSlot > 0);
+
+ if (inputStream.hasBytesAvailable && (!self.stopped))
+ {
+ // This is needed in case we computed a non-integer chunkSizePerSlot, to avoid cumulative errors
+ double cumulativeChunkSizeAfterRead = timingInfo.cumulativeChunkSize + timingInfo.chunkSizePerSlot;
+ NSUInteger chunkSizeToRead = floor(cumulativeChunkSizeAfterRead) - floor(timingInfo.cumulativeChunkSize);
+ timingInfo.cumulativeChunkSize = cumulativeChunkSizeAfterRead;
+
+ if (chunkSizeToRead == 0)
+ {
+ // Nothing to read at this pass, but probably later
+ [self executeOnClientRunLoopAfterDelay:timingInfo.slotTime block:^{
+ [self streamDataForClient:client fromStream:inputStream
+ timingInfo:timingInfo completion:completion];
+ }];
+ } else {
+ uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t)*chunkSizeToRead);
+ NSInteger bytesRead = [inputStream read:buffer maxLength:chunkSizeToRead];
+ if (bytesRead > 0)
+ {
+ NSData * data = [NSData dataWithBytes:buffer length:bytesRead];
+ // Wait for 'slotTime' seconds before sending the chunk.
+ // If bytesRead < chunkSizePerSlot (because we are near the EOF), adjust slotTime proportionally to the bytes remaining
+ [self executeOnClientRunLoopAfterDelay:((double)bytesRead / (double)chunkSizeToRead) * timingInfo.slotTime block:^{
+ [client URLProtocol:self didLoadData:data];
+ [self streamDataForClient:client fromStream:inputStream
+ timingInfo:timingInfo completion:completion];
+ }];
+ }
+ else
+ {
+ if (completion)
+ {
+ // Note: We may also arrive here with no error if we were just at the end of the stream (EOF)
+ // In that case, hasBytesAvailable did return YES (because at the limit of OEF) but nothing were read (because EOF)
+ // But then in that case inputStream.streamError will be nil so that's cool, we won't return an error anyway
+ completion(inputStream.streamError);
+ }
+ }
+ free(buffer);
+ }
+ }
+ else
+ {
+ if (completion)
+ {
+ completion(nil);
+ }
+ }
+}
+
+/////////////////////////////////////////////
+// Delayed execution utility methods
+/////////////////////////////////////////////
+
+- (void)executeOnClientRunLoopAfterDelay:(NSTimeInterval)delayInSeconds block:(dispatch_block_t)block
+{
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
+ dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ CFRunLoopPerformBlock(self.clientRunLoop, kCFRunLoopDefaultMode, block);
+ CFRunLoopWakeUp(self.clientRunLoop);
+ });
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h
new file mode 100644
index 0000000000..0ac0f6e124
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h
@@ -0,0 +1,62 @@
+//
+// OHHTTPStubsResponse+HTTPMessage.h
+// OHHTTPStubs
+//
+// Created by Olivier Halligon on 01/09/13.
+// Copyright (c) 2013 AliSoftware. All rights reserved.
+//
+
+#import "OHHTTPStubsResponse.h"
+
+#ifdef NS_ASSUME_NONNULL_BEGIN
+ NS_ASSUME_NONNULL_BEGIN
+ #define _nullable_ __nullable
+#else
+ #define _nullable_
+#endif
+
+
+/**
+ * Adds support for building stubs from "HTTP Messages" conforming to
+ * the format output by `curl -is`
+ */
+@interface OHHTTPStubsResponse (HTTPMessage)
+
+/*! @name Building a response from HTTP Message data */
+
+// TODO: Try to implement it using NSInputStream someday?
+
+/**
+ * Builds a response given a message data as returned by `curl -is [url]`, that is containing both the headers and the body.
+ *
+ * This method will split the headers and the body and build a OHHTTPStubsReponse accordingly
+ *
+ * @param responseData The NSData containing the whole HTTP response, including the headers and the body
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
++(instancetype)responseWithHTTPMessageData:(NSData*)responseData;
+
+/**
+ * Builds a response given the name of a `"*.response"` file containing both the headers and the body.
+ *
+ * The response file is expected to be in the specified bundle (or the application bundle if nil).
+ * This method will split the headers and the body and build a OHHTTPStubsReponse accordingly
+ *
+ * @param responseName The name of the `"*.response"` file (without extension) containing the whole
+ * HTTP response (including the headers and the body)
+ * @param bundleOrNil The bundle in which the `"*.response"` file is located. If `nil`, the
+ * `[NSBundle bundleForClass:self.class]` will be used.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
+
++(instancetype)responseNamed:(NSString*)responseName
+ inBundle:(NSBundle* _nullable_)bundleOrNil;
+
+
+@end
+
+#ifdef NS_ASSUME_NONNULL_END
+ NS_ASSUME_NONNULL_END
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m
new file mode 100644
index 0000000000..03d0e7a6db
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m
@@ -0,0 +1,54 @@
+//
+// OHHTTPStubsResponse+HTTPMessage.m
+// OHHTTPStubs
+//
+// Created by Olivier Halligon on 01/09/13.
+// Copyright (c) 2013 AliSoftware. All rights reserved.
+//
+
+#import "OHHTTPStubsResponse+HTTPMessage.h"
+
+@implementation OHHTTPStubsResponse (HTTPMessage)
+
+#pragma mark Building response from HTTP Message Data (dump from "curl -is")
+
++(instancetype)responseWithHTTPMessageData:(NSData*)responseData;
+{
+ NSData *data = [NSData data];
+ NSInteger statusCode = 200;
+ NSDictionary *headers = @{};
+
+ CFHTTPMessageRef httpMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE);
+ if (httpMessage)
+ {
+ CFHTTPMessageAppendBytes(httpMessage, responseData.bytes, responseData.length);
+
+ data = responseData; // By default
+
+ if (CFHTTPMessageIsHeaderComplete(httpMessage))
+ {
+ statusCode = (NSInteger)CFHTTPMessageGetResponseStatusCode(httpMessage);
+ headers = (__bridge_transfer NSDictionary *)CFHTTPMessageCopyAllHeaderFields(httpMessage);
+ data = (__bridge_transfer NSData *)CFHTTPMessageCopyBody(httpMessage);
+ }
+ CFRelease(httpMessage);
+ }
+
+ return [self responseWithData:data
+ statusCode:(int)statusCode
+ headers:headers];
+}
+
++(instancetype)responseNamed:(NSString*)responseName
+ inBundle:(NSBundle*)responsesBundle
+{
+ NSURL *responseURL = [responsesBundle?:[NSBundle bundleForClass:self.class] URLForResource:responseName
+ withExtension:@"response"];
+
+ NSData *responseData = [NSData dataWithContentsOfURL:responseURL];
+ NSAssert(responseData, @"Could not find HTTP response named '%@' in bundle '%@'", responseName, responsesBundle);
+
+ return [self responseWithHTTPMessageData:responseData];
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h
new file mode 100644
index 0000000000..fc8719df0d
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h
@@ -0,0 +1,47 @@
+//
+// OHHTTPStubsResponse+JSON.h
+// OHHTTPStubs
+//
+// Created by Olivier Halligon on 01/09/13.
+// Copyright (c) 2013 AliSoftware. All rights reserved.
+//
+
+#import "OHHTTPStubsResponse.h"
+
+#ifdef NS_ASSUME_NONNULL_BEGIN
+ NS_ASSUME_NONNULL_BEGIN
+ #define _nullable_ __nullable
+#else
+ #define _nullable_
+#endif
+
+
+/**
+ * Adds convenience methods to manipulate JSON objects directly.
+ * Pass in an `NSDictionary` or `NSArray` to generate a corresponding JSON output.
+ */
+@interface OHHTTPStubsResponse (JSON)
+
+/**
+ * Builds a response given a JSON object for the response body, status code, and headers.
+ *
+ * @param jsonObject Object representing the response body.
+ * Typically a `NSDictionary`; may be any object accepted by `+[NSJSONSerialization dataWithJSONObject:options:error:]`
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ * If a "Content-Type" header is not included, "Content-Type: application/json" will be added.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note This method typically calls `responseWithData:statusCode:headers:`, passing the serialized JSON
+ * object as the data parameter and adding the Content-Type header if necessary.
+ */
++ (instancetype)responseWithJSONObject:(id)jsonObject
+ statusCode:(int)statusCode
+ headers:(NSDictionary * _nullable_)httpHeaders;
+
+@end
+
+#ifdef NS_ASSUME_NONNULL_END
+ NS_ASSUME_NONNULL_END
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m
new file mode 100644
index 0000000000..aebcb99080
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m
@@ -0,0 +1,31 @@
+//
+// OHHTTPStubsResponse+JSON.m
+// OHHTTPStubs
+//
+// Created by Olivier Halligon on 01/09/13.
+// Copyright (c) 2013 AliSoftware. All rights reserved.
+//
+
+#import "OHHTTPStubsResponse+JSON.h"
+
+@implementation OHHTTPStubsResponse (JSON)
+
+/*! @name Building a response from JSON objects */
+
++ (instancetype)responseWithJSONObject:(id)jsonObject
+ statusCode:(int)statusCode
+ headers:(NSDictionary *)httpHeaders
+{
+ if (!httpHeaders[@"Content-Type"])
+ {
+ NSMutableDictionary* mutableHeaders = [NSMutableDictionary dictionaryWithDictionary:httpHeaders];
+ mutableHeaders[@"Content-Type"] = @"application/json";
+ httpHeaders = [NSDictionary dictionaryWithDictionary:mutableHeaders]; // make immutable again
+ }
+
+ return [self responseWithData:[NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:nil]
+ statusCode:statusCode
+ headers:httpHeaders];
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h
new file mode 100644
index 0000000000..27f487f9fa
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h
@@ -0,0 +1,269 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Imports
+
+#import <Foundation/Foundation.h>
+#import "Compatibility.h"
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Defines & Constants
+
+// Non-standard download speeds
+extern const double
+OHHTTPStubsDownloadSpeed1KBPS, // 1.0 KB per second
+OHHTTPStubsDownloadSpeedSLOW; // 1.5 KB per second
+
+// Standard download speeds.
+extern const double
+OHHTTPStubsDownloadSpeedGPRS,
+OHHTTPStubsDownloadSpeedEDGE,
+OHHTTPStubsDownloadSpeed3G,
+OHHTTPStubsDownloadSpeed3GPlus,
+OHHTTPStubsDownloadSpeedWifi;
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Interface
+
+/**
+ * Stubs Response. This describes a stubbed response to be returned by the URL Loading System,
+ * including its HTTP headers, body, statusCode and response time.
+ */
+@interface OHHTTPStubsResponse : NSObject
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Properties
+
+/**
+ * The headers to use for the fake response
+ */
+@property(nonatomic, strong, nullable) NSDictionary* httpHeaders;
+/**
+ * The HTTP status code to use for the fake response
+ */
+@property(nonatomic, assign) int statusCode;
+/**
+ * The inputStream used when sending the response.
+ * @note You generally don't manipulate this directly.
+ */
+@property(nonatomic, strong, nullable) NSInputStream* inputStream;
+/**
+ * The size of the fake response body, in bytes.
+ */
+@property(nonatomic, assign) unsigned long long dataSize;
+/**
+ * The duration to wait before faking receiving the response headers.
+ *
+ * Defaults to 0.0.
+ */
+@property(nonatomic, assign) NSTimeInterval requestTime;
+/**
+ * The duration to use to send the fake response body.
+ *
+ * @note if responseTime<0, it is interpreted as a download speed in KBps ( -200 => 200KB/s )
+ */
+@property(nonatomic, assign) NSTimeInterval responseTime;
+/**
+ * The fake error to generate to simulate a network error.
+ *
+ * If `error` is non-`nil`, the request will result in a failure and no response will be sent.
+ */
+@property(nonatomic, strong, nullable) NSError* error;
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Commodity Constructors
+/*! @name Commodity */
+
+/* -------------------------------------------------------------------------- */
+#pragma mark > Building response from NSData
+
+/**
+ * Builds a response given raw data.
+ *
+ * @note Internally calls `-initWithInputStream:dataSize:statusCode:headers:` with and inputStream built from the NSData.
+ *
+ * @param data The raw data to return in the response
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
++(instancetype)responseWithData:(NSData*)data
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders;
+
+
+/* -------------------------------------------------------------------------- */
+#pragma mark > Building response from a file
+
+/**
+ * Builds a response given a file path, the status code and headers.
+ *
+ * @param filePath The file path that contains the response body to return.
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note It is encouraged to use the OHPathHelpers functions & macros to build
+ * the filePath parameter easily
+ */
++(instancetype)responseWithFileAtPath:(NSString *)filePath
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders;
+
+/* -------------------------------------------------------------------------- */
+#pragma mark > Building an error response
+
+/**
+ * Builds a response that corresponds to the given error
+ *
+ * @param error The error to use in the stubbed response.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note For example you could use an error like `[NSError errorWithDomain:NSURLErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:nil]`
+ */
++(instancetype)responseWithError:(NSError*)error;
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Commotidy Setters
+
+/**
+ * Set the `responseTime` of the `OHHTTPStubsResponse` and return `self`. Useful for chaining method calls.
+ *
+ * _Usage example:_
+ * <pre>return [[OHHTTPStubsReponse responseWithData:data statusCode:200 headers:nil] responseTime:5.0];</pre>
+ *
+ * @param responseTime If positive, the amount of time used to send the entire response.
+ * If negative, the rate in KB/s at which to send the response data.
+ * Useful to simulate slow networks for example. You may use the
+ * _OHHTTPStubsDownloadSpeed…_ constants here.
+ *
+ * @return `self` (= the same `OHHTTPStubsResponse` that was the target of this method).
+ * Returning `self` is useful for chaining method calls.
+ */
+-(instancetype)responseTime:(NSTimeInterval)responseTime;
+
+/**
+ * Set both the `requestTime` and the `responseTime` of the `OHHTTPStubsResponse` at once.
+ * Useful for chaining method calls.
+ *
+ * _Usage example:_
+ * <pre>return [[OHHTTPStubsReponse responseWithData:data statusCode:200 headers:nil]
+ * requestTime:1.0 responseTime:5.0];</pre>
+ *
+ * @param requestTime The time to wait before the response begins to send. This value must be greater than or equal to zero.
+ * @param responseTime If positive, the amount of time used to send the entire response.
+ * If negative, the rate in KB/s at which to send the response data.
+ * Useful to simulate slow networks for example. You may use the
+ * _OHHTTPStubsDownloadSpeed…_ constants here.
+ *
+ * @return `self` (= the same `OHHTTPStubsResponse` that was the target of this method). Useful for chaining method calls.
+ */
+-(instancetype)requestTime:(NSTimeInterval)requestTime responseTime:(NSTimeInterval)responseTime;
+
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Initializers
+/*! @name Initializers */
+
+/**
+ * Designated empty initializer
+ *
+ * @return An empty `OHHTTPStubsResponse` on which you need to set either an error or a statusCode, httpHeaders, inputStream and dataSize.
+ *
+ * @note This is not recommended to use this method directly. You should use `initWithInputStream:dataSize:statusCode:headers:` instead.
+ */
+-(instancetype)init NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Designed initializer. Initialize a response with the given input stream, dataSize,
+ * statusCode and headers.
+ *
+ * @param inputStream The input stream that will provide the data to return in the response
+ * @param dataSize The size of the data in the stream.
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note You will probably never need to call this method yourself. Prefer the other initializers (that will call this method eventually)
+ */
+-(instancetype)initWithInputStream:(NSInputStream*)inputStream
+ dataSize:(unsigned long long)dataSize
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders NS_DESIGNATED_INITIALIZER;
+
+
+/**
+ * Initialize a response with a given file path, statusCode and headers.
+ *
+ * @param filePath The file path of the data to return in the response
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note This method simply builds the NSInputStream, compute the file size, and then call `-initWithInputStream:dataSize:statusCode:headers:`
+ */
+-(instancetype)initWithFileAtPath:(NSString*)filePath
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders;
+
+
+/**
+ * Initialize a response with the given data, statusCode and headers.
+ *
+ * @param data The raw data to return in the response
+ * @param statusCode The HTTP Status Code to use in the response
+ * @param httpHeaders The HTTP Headers to return in the response
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ */
+-(instancetype)initWithData:(NSData*)data
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders;
+
+
+/**
+ * Designed initializer. Initialize a response with the given error.
+ *
+ * @param error The error to use in the stubbed response.
+ *
+ * @return An `OHHTTPStubsResponse` describing the corresponding response to return by the stub
+ *
+ * @note For example you could use an error like `[NSError errorWithDomain:NSURLErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:nil]`
+ */
+-(instancetype)initWithError:(NSError*)error NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m
new file mode 100644
index 0000000000..db8d7efa79
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m
@@ -0,0 +1,194 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+#if ! __has_feature(objc_arc)
+#error This file is expected to be compiled with ARC turned ON
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Imports
+
+#import "OHHTTPStubsResponse.h"
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Defines & Constants
+const double OHHTTPStubsDownloadSpeed1KBPS =- 8 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeedSLOW =- 12 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeedGPRS =- 56 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeedEDGE =- 128 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeed3G =- 3200 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeed3GPlus =- 7200 / 8; // kbps -> KB/s
+const double OHHTTPStubsDownloadSpeedWifi =- 12000 / 8; // kbps -> KB/s
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Implementation
+
+@implementation OHHTTPStubsResponse
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Commodity Constructors
+
+
+#pragma mark > Building response from NSData
+
++(instancetype)responseWithData:(NSData*)data
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders
+{
+ OHHTTPStubsResponse* response = [[self alloc] initWithData:data
+ statusCode:statusCode
+ headers:httpHeaders];
+ return response;
+}
+
+
+#pragma mark > Building response from a file
+
++(instancetype)responseWithFileAtPath:(NSString *)filePath
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary *)httpHeaders
+{
+ OHHTTPStubsResponse* response = [[self alloc] initWithFileAtPath:filePath
+ statusCode:statusCode
+ headers:httpHeaders];
+ return response;
+}
+
+
+#pragma mark > Building an error response
+
++(instancetype)responseWithError:(NSError*)error
+{
+ OHHTTPStubsResponse* response = [[self alloc] initWithError:error];
+ return response;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Commotidy Setters
+
+-(instancetype)responseTime:(NSTimeInterval)responseTime
+{
+ _responseTime = responseTime;
+ return self;
+}
+
+-(instancetype)requestTime:(NSTimeInterval)requestTime responseTime:(NSTimeInterval)responseTime
+{
+ _requestTime = requestTime;
+ _responseTime = responseTime;
+ return self;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Initializers
+
+-(instancetype)init
+{
+ self = [super init];
+ return self;
+}
+
+-(instancetype)initWithInputStream:(NSInputStream*)inputStream
+ dataSize:(unsigned long long)dataSize
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders
+{
+ self = [super init];
+ if (self)
+ {
+ _inputStream = inputStream;
+ _dataSize = dataSize;
+ _statusCode = statusCode;
+ NSMutableDictionary * headers = [NSMutableDictionary dictionaryWithDictionary:httpHeaders];
+ static NSString *const ContentLengthHeader = @"Content-Length";
+ if (!headers[ContentLengthHeader])
+ {
+ headers[ContentLengthHeader] = [NSString stringWithFormat:@"%llu",_dataSize];
+ }
+ _httpHeaders = [NSDictionary dictionaryWithDictionary:headers];
+ }
+ return self;
+}
+
+-(instancetype)initWithFileAtPath:(NSString*)filePath
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders
+{
+ NSInputStream* inputStream;
+ if (filePath)
+ {
+ inputStream = [NSInputStream inputStreamWithFileAtPath:filePath];
+ }
+ else
+ {
+ NSLog(@"%s: nil file path. Returning empty data", __PRETTY_FUNCTION__);
+ inputStream = [NSInputStream inputStreamWithData:[NSData data]];
+ }
+
+ NSDictionary* attributes = [NSFileManager.defaultManager attributesOfItemAtPath:filePath error:nil];
+ unsigned long long fileSize = [[attributes valueForKey:NSFileSize] unsignedLongLongValue];
+ self = [self initWithInputStream:inputStream
+ dataSize:fileSize
+ statusCode:statusCode
+ headers:httpHeaders];
+ return self;
+}
+
+-(instancetype)initWithData:(NSData*)data
+ statusCode:(int)statusCode
+ headers:(nullable NSDictionary*)httpHeaders
+{
+ NSInputStream* inputStream = [NSInputStream inputStreamWithData:data?:[NSData data]];
+ self = [self initWithInputStream:inputStream
+ dataSize:data.length
+ statusCode:statusCode
+ headers:httpHeaders];
+ return self;
+}
+
+-(instancetype)initWithError:(NSError*)error
+{
+ self = [super init];
+ if (self) {
+ _error = error;
+ }
+ return self;
+}
+
+-(NSString*)debugDescription
+{
+ return [NSString stringWithFormat:@"<%@ %p requestTime:%f responseTime:%f status:%d dataSize:%llu>",
+ self.class, self, self.requestTime, self.responseTime, self.statusCode, self.dataSize];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Accessors
+
+-(void)setRequestTime:(NSTimeInterval)requestTime
+{
+ NSAssert(requestTime >= 0, @"Invalid Request Time (%f) for OHHTTPStubResponse. Request time must be greater than or equal to zero",requestTime);
+ _requestTime = requestTime;
+}
+
+@end
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h
new file mode 100644
index 0000000000..aa250547b8
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h
@@ -0,0 +1,77 @@
+//
+// OHPathHelpers.h
+// Pods
+//
+// Created by Olivier Halligon on 18/04/2015.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+#ifdef NS_ASSUME_NONNULL_BEGIN
+ NS_ASSUME_NONNULL_BEGIN
+ #define _nullable_ __nullable
+#else
+ #define _nullable_
+#endif
+
+
+/**
+ * Useful function to build a path given a file name and a class.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ * @param inBundleForClass The class of the caller, used to determine the current bundle
+ * in which the file is supposed to be located.
+ * You should typically pass `self.class` (ObjC) or
+ * `self.dynamicType` (Swift) when calling this function.
+ *
+ * @return The path of the given file in the same bundle as the inBundleForClass class
+ */
+NSString* _nullable_ OHPathForFile(NSString* fileName, Class inBundleForClass);
+
+/**
+ * Useful function to build a path given a file name and a bundle.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ * @param bundle The bundle in which the file is supposed to be located.
+ * This parameter can't be null.
+ *
+ * @return The path of the given file in given bundle
+ *
+ * @note You should avoid using `[NSBundle mainBundle]` for the `bundle` parameter,
+ * as in the context of Unit Tests, this points to the Simulator's bundle,
+ * not the bundle of the app under test. That's why `nil` is not an acceptable
+ * value (so you won't expect it to default to the `mainBundle`).
+ * You should use `[NSBundle bundleForClass:]` instead.
+ */
+NSString* _nullable_ OHPathForFileInBundle(NSString* fileName, NSBundle* bundle);
+
+/**
+ * Useful function to build a path to a file in the Documents's directory in the
+ * app sandbox, used by iTunes File Sharing for example.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ *
+ * @return The path of the file in the Documents directory in your App Sandbox
+ */
+NSString* _nullable_ OHPathForFileInDocumentsDir(NSString* fileName);
+
+
+
+/**
+ * Useful function to build an NSBundle located in the application's resources simply from its name
+ *
+ * @param bundleBasename The base name, without extension (extension is assumed to be ".bundle").
+ * @param inBundleForClass The class of the caller, used to determine the current bundle
+ * in which the file is supposed to be located.
+ * You should typically pass `self.class` (ObjC) or
+ * `self.dynamicType` (Swift) when calling this function.
+ *
+ * @return The NSBundle object representing the bundle with the given basename located in your application's resources.
+ */
+NSBundle* _nullable_ OHResourceBundle(NSString* bundleBasename, Class inBundleForClass);
+
+
+#ifdef NS_ASSUME_NONNULL_END
+ NS_ASSUME_NONNULL_END
+#endif
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m
new file mode 100644
index 0000000000..cac24a636a
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m
@@ -0,0 +1,35 @@
+//
+// OHPathHelpers.m
+// Pods
+//
+// Created by Olivier Halligon on 18/04/2015.
+//
+//
+
+#import "OHPathHelpers.h"
+
+NSString* OHPathForFile(NSString* fileName, Class inBundleForClass)
+{
+ NSBundle* bundle = [NSBundle bundleForClass:inBundleForClass];
+ return OHPathForFileInBundle(fileName, bundle);
+}
+
+NSString* OHPathForFileInBundle(NSString* fileName, NSBundle* bundle)
+{
+ return [bundle pathForResource:[fileName stringByDeletingPathExtension]
+ ofType:[fileName pathExtension]];
+}
+
+NSString* OHPathForFileInDocumentsDir(NSString* fileName)
+{
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *basePath = (paths.count > 0) ? [paths objectAtIndex:0] : nil;
+ return [basePath stringByAppendingPathComponent:fileName];
+}
+
+NSBundle* OHResourceBundleForClass(NSString* bundleBasename, Class inBundleForClass)
+{
+ NSBundle* classBundle = [NSBundle bundleForClass:inBundleForClass];
+ return [NSBundle bundleWithPath:[classBundle pathForResource:bundleBasename
+ ofType:@"bundle"]];
+} \ No newline at end of file
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h
new file mode 100644
index 0000000000..b3c301acdd
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h
@@ -0,0 +1,86 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#import <Foundation/Foundation.h>
+#import <OHHTTPStubs/Compatibility.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Useful function to build a path given a file name and a class.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ * @param inBundleForClass The class of the caller, used to determine the current bundle
+ * in which the file is supposed to be located.
+ * You should typically pass `self.class` (ObjC) or
+ * `self.dynamicType` (Swift) when calling this function.
+ *
+ * @return The path of the given file in the same bundle as the inBundleForClass class
+ */
+NSString* __nullable OHPathForFile(NSString* fileName, Class inBundleForClass);
+
+/**
+ * Useful function to build a path given a file name and a bundle.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ * @param bundle The bundle in which the file is supposed to be located.
+ * This parameter can't be null.
+ *
+ * @return The path of the given file in given bundle
+ *
+ * @note You should avoid using `[NSBundle mainBundle]` for the `bundle` parameter,
+ * as in the context of Unit Tests, this points to the Simulator's bundle,
+ * not the bundle of the app under test. That's why `nil` is not an acceptable
+ * value (so you won't expect it to default to the `mainBundle`).
+ * You should use `[NSBundle bundleForClass:]` instead.
+ */
+NSString* __nullable OHPathForFileInBundle(NSString* fileName, NSBundle* bundle);
+
+/**
+ * Useful function to build a path to a file in the Documents's directory in the
+ * app sandbox, used by iTunes File Sharing for example.
+ *
+ * @param fileName The name of the file to get the path to, including file extension
+ *
+ * @return The path of the file in the Documents directory in your App Sandbox
+ */
+NSString* __nullable OHPathForFileInDocumentsDir(NSString* fileName);
+
+
+
+/**
+ * Useful function to build an NSBundle located in the application's resources simply from its name
+ *
+ * @param bundleBasename The base name, without extension (extension is assumed to be ".bundle").
+ * @param inBundleForClass The class of the caller, used to determine the current bundle
+ * in which the file is supposed to be located.
+ * You should typically pass `self.class` (ObjC) or
+ * `self.dynamicType` (Swift) when calling this function.
+ *
+ * @return The NSBundle object representing the bundle with the given basename located in your application's resources.
+ */
+NSBundle* __nullable OHResourceBundle(NSString* bundleBasename, Class inBundleForClass);
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m
new file mode 100644
index 0000000000..18b769e45a
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m
@@ -0,0 +1,52 @@
+/***********************************************************************************
+ *
+ * Copyright (c) 2012 Olivier Halligon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ ***********************************************************************************/
+
+
+#import <OHHTTPStubs/OHPathHelpers.h>
+
+NSString* __nullable OHPathForFile(NSString* fileName, Class inBundleForClass)
+{
+ NSBundle* bundle = [NSBundle bundleForClass:inBundleForClass];
+ return OHPathForFileInBundle(fileName, bundle);
+}
+
+NSString* __nullable OHPathForFileInBundle(NSString* fileName, NSBundle* bundle)
+{
+ return [bundle pathForResource:[fileName stringByDeletingPathExtension]
+ ofType:[fileName pathExtension]];
+}
+
+NSString* __nullable OHPathForFileInDocumentsDir(NSString* fileName)
+{
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *basePath = (paths.count > 0) ? paths[0] : nil;
+ return [basePath stringByAppendingPathComponent:fileName];
+}
+
+NSBundle* __nullable OHResourceBundle(NSString* bundleBasename, Class inBundleForClass)
+{
+ NSBundle* classBundle = [NSBundle bundleForClass:inBundleForClass];
+ return [NSBundle bundleWithPath:[classBundle pathForResource:bundleBasename
+ ofType:@"bundle"]];
+}
diff --git a/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift
new file mode 100644
index 0000000000..5229dcb808
--- /dev/null
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift
@@ -0,0 +1,179 @@
+/***********************************************************************************
+*
+* Copyright (c) 2012 Olivier Halligon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+***********************************************************************************/
+
+/**
+ * Swift Helpers
+ */
+
+
+
+// MARK: Syntaxic Sugar for OHHTTPStubs
+
+/**
+ * Helper to return a `OHHTTPStubsResponse` given a fixture path, status code and optional headers.
+ *
+ * - Parameter filePath: the path of the file fixture to use for the response
+ * - Parameter status: the status code to use for the response
+ * - Parameter headers: the HTTP headers to use for the response
+ *
+ * - Returns: The `OHHTTPStubsResponse` instance that will stub with the given status code
+ * & headers, and use the file content as the response body.
+ */
+public func fixture(filePath: String, status: Int32 = 200, headers: [NSObject: AnyObject]?) -> OHHTTPStubsResponse {
+ return OHHTTPStubsResponse(fileAtPath: filePath, statusCode: status, headers: headers)
+}
+
+/**
+ * Helper to call the stubbing function in a more concise way?
+ *
+ * - Parameter condition: the matcher block that determine if the request will be stubbed
+ * - Parameter response: the stub reponse to use if the request is stubbed
+ *
+ * - Returns: The opaque `OHHTTPStubsDescriptor` that uniquely identifies the stub
+ * and can be later used to remove it with `removeStub:`
+ */
+public func stub(condition: OHHTTPStubsTestBlock, response: OHHTTPStubsResponseBlock) -> OHHTTPStubsDescriptor {
+ return OHHTTPStubs.stubRequestsPassingTest(condition, withStubResponse: response)
+}
+
+
+
+// MARK: Create OHHTTPStubsTestBlock matchers
+
+/**
+ * Matcher for testing an `NSURLRequest`'s **scheme**.
+ *
+ * - Parameter scheme: The scheme to match
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that succeeds only if the request
+ * has the given scheme
+ */
+public func isScheme(scheme: String) -> OHHTTPStubsTestBlock {
+ return { req in req.URL?.scheme == scheme }
+}
+
+/**
+ * Matcher for testing an `NSURLRequest`'s **host**.
+ *
+ * - Parameter host: The host to match
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that succeeds only if the request
+ * has the given host
+ */
+public func isHost(host: String) -> OHHTTPStubsTestBlock {
+ return { req in req.URL?.host == host }
+}
+
+/**
+ * Matcher for testing an `NSURLRequest`'s **path**.
+ *
+ * - Parameter path: The path to match
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that succeeds only if the request
+ * has exactly the given path
+ *
+ * - Note: URL paths are usually absolute and thus starts with a '/' (which you
+ * should include in the `path` parameter unless you're testing relative URLs)
+ */
+public func isPath(path: String) -> OHHTTPStubsTestBlock {
+ return { req in req.URL?.path == path }
+}
+
+/**
+ * Matcher for testing an `NSURLRequest`'s **path extension**.
+ *
+ * - Parameter ext: The file extension to match (without the dot)
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that succeeds only if the request path
+ * ends with the given extension
+ */
+public func isExtension(ext: String) -> OHHTTPStubsTestBlock {
+ return { req in req.URL?.pathExtension == ext }
+}
+
+/**
+ * Matcher for testing an `NSURLRequest`'s **query parameters**.
+ *
+ * - Parameter params: The dictionary of query parameters to check the presence for
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that succeeds if the request contains
+ * the given query parameters with the given value.
+ *
+ * - Note: There is a difference between:
+ * (1) using `[q:""]`, which matches a query parameter "?q=" with an empty value, and
+ * (2) using `[q:nil]`, which matches a query parameter "?q" without a value at all
+ */
+public func containsQueryParams(params: [String:String?]) -> OHHTTPStubsTestBlock {
+ return { req in
+ if let url = req.URL {
+ let comps = NSURLComponents(URL: url, resolvingAgainstBaseURL: true)
+ if let queryItems = comps?.queryItems {
+ for (k,v) in params {
+ if queryItems.filter({ qi in qi.name == k && qi.value == v }).count == 0 { return false }
+ }
+ return true
+ }
+ }
+ return false
+ }
+}
+
+
+
+// MARK: Operators on OHHTTPStubsTestBlock
+
+/**
+ * Combine different `OHHTTPStubsTestBlock` matchers with an 'OR' operation.
+ *
+ * - Parameter lhs: the first matcher to test
+ * - Parameter rhs: the second matcher to test
+ *
+ * - Returns: a matcher (`OHHTTPStubsTestBlock`) that succeeds if either of the given matchers succeeds
+ */
+public func || (lhs: OHHTTPStubsTestBlock, rhs: OHHTTPStubsTestBlock) -> OHHTTPStubsTestBlock {
+ return { req in lhs(req) || rhs(req) }
+}
+
+/**
+ * Combine different `OHHTTPStubsTestBlock` matchers with an 'AND' operation.
+ *
+ * - Parameter lhs: the first matcher to test
+ * - Parameter rhs: the second matcher to test
+ *
+ * - Returns: a matcher (`OHHTTPStubsTestBlock`) that only succeeds if both of the given matchers succeeds
+ */
+public func && (lhs: OHHTTPStubsTestBlock, rhs: OHHTTPStubsTestBlock) -> OHHTTPStubsTestBlock {
+ return { req in lhs(req) && rhs(req) }
+}
+
+/**
+ * Create the opposite of a given `OHHTTPStubsTestBlock` matcher.
+ *
+ * - Parameter expr: the matcher to negate
+ *
+ * - Returns: a matcher (OHHTTPStubsTestBlock) that only succeeds if the expr matcher fails
+ */
+public prefix func ! (expr: OHHTTPStubsTestBlock) -> OHHTTPStubsTestBlock {
+ return { req in !expr(req) }
+}