30 |
31 | #import "Compatibility.h"
32 |
33 | ////////////////////////////////////////////////////////////////////////////////
34 | #pragma mark - Defines & Constants
35 |
36 | // Non-standard download speeds
37 | extern const double
38 | OHHTTPStubsDownloadSpeed1KBPS, // 1.0 KB per second
39 | OHHTTPStubsDownloadSpeedSLOW; // 1.5 KB per second
40 |
41 | // Standard download speeds.
42 | extern const double
43 | OHHTTPStubsDownloadSpeedGPRS,
44 | OHHTTPStubsDownloadSpeedEDGE,
45 | OHHTTPStubsDownloadSpeed3G,
46 | OHHTTPStubsDownloadSpeed3GPlus,
47 | OHHTTPStubsDownloadSpeedWifi;
48 |
49 |
50 | NS_ASSUME_NONNULL_BEGIN
51 |
52 | ////////////////////////////////////////////////////////////////////////////////
53 | #pragma mark - Interface
54 |
55 | /**
56 | * Stubs Response. This describes a stubbed response to be returned by the URL Loading System,
57 | * including its HTTP headers, body, statusCode and response time.
58 | */
59 | @interface HTTPStubsResponse : NSObject
60 |
61 | ////////////////////////////////////////////////////////////////////////////////
62 | #pragma mark - Properties
63 |
64 | /**
65 | * The headers to use for the fake response
66 | */
67 | @property(nonatomic, strong, nullable) NSDictionary* httpHeaders;
68 | /**
69 | * The HTTP status code to use for the fake response
70 | */
71 | @property(nonatomic, assign) int statusCode;
72 | /**
73 | * The inputStream used when sending the response.
74 | * @note You generally don't manipulate this directly.
75 | */
76 | @property(nonatomic, strong, nullable) NSInputStream* inputStream;
77 | /**
78 | * The size of the fake response body, in bytes.
79 | */
80 | @property(nonatomic, assign) unsigned long long dataSize;
81 | /**
82 | * The duration to wait before faking receiving the response headers.
83 | *
84 | * Defaults to 0.0.
85 | */
86 | @property(nonatomic, assign) NSTimeInterval requestTime;
87 | /**
88 | * The duration to use to send the fake response body.
89 | *
90 | * @note if responseTime<0, it is interpreted as a download speed in KBps ( -200 => 200KB/s )
91 | */
92 | @property(nonatomic, assign) NSTimeInterval responseTime;
93 | /**
94 | * The fake error to generate to simulate a network error.
95 | *
96 | * If `error` is non-`nil`, the request will result in a failure and no response will be sent.
97 | */
98 | @property(nonatomic, strong, nullable) NSError* error;
99 |
100 |
101 | ////////////////////////////////////////////////////////////////////////////////
102 | #pragma mark - Commodity Constructors
103 | /*! @name Commodity */
104 |
105 | /* -------------------------------------------------------------------------- */
106 | #pragma mark > Building response from NSData
107 |
108 | /**
109 | * Builds a response given raw data.
110 | *
111 | * @note Internally calls `-initWithInputStream:dataSize:statusCode:headers:` with and inputStream built from the NSData.
112 | *
113 | * @param data The raw data to return in the response
114 | * @param statusCode The HTTP Status Code to use in the response
115 | * @param httpHeaders The HTTP Headers to return in the response
116 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
117 | */
118 | +(instancetype)responseWithData:(NSData*)data
119 | statusCode:(int)statusCode
120 | headers:(nullable NSDictionary*)httpHeaders;
121 |
122 |
123 | /* -------------------------------------------------------------------------- */
124 | #pragma mark > Building response from a file
125 |
126 | /**
127 | * Builds a response given a file path, the status code and headers.
128 | *
129 | * @param filePath The file path that contains the response body to return.
130 | * @param statusCode The HTTP Status Code to use in the response
131 | * @param httpHeaders The HTTP Headers to return in the response
132 | *
133 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
134 | *
135 | * @note It is encouraged to use the OHPathHelpers functions & macros to build
136 | * the filePath parameter easily
137 | */
138 | +(instancetype)responseWithFileAtPath:(NSString *)filePath
139 | statusCode:(int)statusCode
140 | headers:(nullable NSDictionary*)httpHeaders;
141 |
142 |
143 | /**
144 | * Builds a response given a URL, the status code, and headers.
145 | *
146 | * @param fileURL The URL for the data to return in the response
147 | * @param statusCode The HTTP Status Code to use in the response
148 | * @param httpHeaders The HTTP Headers to return in the response
149 | *
150 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
151 | *
152 | * @note This method applies only to URLs that represent file system resources
153 | */
154 | +(instancetype)responseWithFileURL:(NSURL *)fileURL
155 | statusCode:(int)statusCode
156 | headers:(nullable NSDictionary *)httpHeaders;
157 |
158 | /* -------------------------------------------------------------------------- */
159 | #pragma mark > Building an error response
160 |
161 | /**
162 | * Builds a response that corresponds to the given error
163 | *
164 | * @param error The error to use in the stubbed response.
165 | *
166 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
167 | *
168 | * @note For example you could use an error like `[NSError errorWithDomain:NSURLErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:nil]`
169 | */
170 | +(instancetype)responseWithError:(NSError*)error;
171 |
172 |
173 | ////////////////////////////////////////////////////////////////////////////////
174 | #pragma mark - Commotidy Setters
175 |
176 | /**
177 | * Set the `responseTime` of the `HTTPStubsResponse` and return `self`. Useful for chaining method calls.
178 | *
179 | * _Usage example:_
180 | * return [[HTTPStubsResponse responseWithData:data statusCode:200 headers:nil] responseTime:5.0];
181 | *
182 | * @param responseTime If positive, the amount of time used to send the entire response.
183 | * If negative, the rate in KB/s at which to send the response data.
184 | * Useful to simulate slow networks for example. You may use the
185 | * _OHHTTPStubsDownloadSpeed…_ constants here.
186 | *
187 | * @return `self` (= the same `HTTPStubsResponse` that was the target of this method).
188 | * Returning `self` is useful for chaining method calls.
189 | */
190 | -(instancetype)responseTime:(NSTimeInterval)responseTime;
191 |
192 | /**
193 | * Set both the `requestTime` and the `responseTime` of the `HTTPStubsResponse` at once.
194 | * Useful for chaining method calls.
195 | *
196 | * _Usage example:_
197 | * return [[HTTPStubsResponse responseWithData:data statusCode:200 headers:nil]
198 | * requestTime:1.0 responseTime:5.0];
199 | *
200 | * @param requestTime The time to wait before the response begins to send. This value must be greater than or equal to zero.
201 | * @param responseTime If positive, the amount of time used to send the entire response.
202 | * If negative, the rate in KB/s at which to send the response data.
203 | * Useful to simulate slow networks for example. You may use the
204 | * _OHHTTPStubsDownloadSpeed…_ constants here.
205 | *
206 | * @return `self` (= the same `HTTPStubsResponse` that was the target of this method). Useful for chaining method calls.
207 | */
208 | -(instancetype)requestTime:(NSTimeInterval)requestTime responseTime:(NSTimeInterval)responseTime;
209 |
210 |
211 | ////////////////////////////////////////////////////////////////////////////////
212 | #pragma mark - Initializers
213 | /*! @name Initializers */
214 |
215 | /**
216 | * Designated empty initializer
217 | *
218 | * @return An empty `HTTPStubsResponse` on which you need to set either an error or a statusCode, httpHeaders, inputStream and dataSize.
219 | *
220 | * @note This is not recommended to use this method directly. You should use `initWithInputStream:dataSize:statusCode:headers:` instead.
221 | */
222 | -(instancetype)init NS_DESIGNATED_INITIALIZER;
223 |
224 | /**
225 | * Designed initializer. Initialize a response with the given input stream, dataSize,
226 | * statusCode and headers.
227 | *
228 | * @param inputStream The input stream that will provide the data to return in the response
229 | * @param dataSize The size of the data in the stream.
230 | * @param statusCode The HTTP Status Code to use in the response
231 | * @param httpHeaders The HTTP Headers to return in the response
232 | *
233 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
234 | *
235 | * @note You will probably never need to call this method yourself. Prefer the other initializers (that will call this method eventually)
236 | */
237 | -(instancetype)initWithInputStream:(NSInputStream*)inputStream
238 | dataSize:(unsigned long long)dataSize
239 | statusCode:(int)statusCode
240 | headers:(nullable NSDictionary*)httpHeaders NS_DESIGNATED_INITIALIZER;
241 |
242 |
243 | /**
244 | * Initialize a response with a given file path, statusCode and headers.
245 | *
246 | * @param filePath The file path of the data to return in the response
247 | * @param statusCode The HTTP Status Code to use in the response
248 | * @param httpHeaders The HTTP Headers to return in the response
249 | *
250 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
251 | *
252 | * @note This method simply builds the NSInputStream, compute the file size, and then call `-initWithInputStream:dataSize:statusCode:headers:`
253 | */
254 | -(instancetype)initWithFileAtPath:(NSString*)filePath
255 | statusCode:(int)statusCode
256 | headers:(nullable NSDictionary*)httpHeaders;
257 |
258 |
259 | /**
260 | * Initialize a response with a given URL, statusCode and headers.
261 | *
262 | * @param fileURL The URL for the data to return in the response
263 | * @param statusCode The HTTP Status Code to use in the response
264 | * @param httpHeaders The HTTP Headers to return in the response
265 | *
266 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
267 | *
268 | * @note This method applies only to URLs that represent file system resources
269 | */
270 | -(instancetype)initWithFileURL:(NSURL *)fileURL
271 | statusCode:(int)statusCode
272 | headers:(nullable NSDictionary *)httpHeaders;
273 |
274 | /**
275 | * Initialize a response with the given data, statusCode and headers.
276 | *
277 | * @param data The raw data to return in the response
278 | * @param statusCode The HTTP Status Code to use in the response
279 | * @param httpHeaders The HTTP Headers to return in the response
280 | *
281 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
282 | */
283 | -(instancetype)initWithData:(NSData*)data
284 | statusCode:(int)statusCode
285 | headers:(nullable NSDictionary*)httpHeaders;
286 |
287 |
288 | /**
289 | * Designed initializer. Initialize a response with the given error.
290 | *
291 | * @param error The error to use in the stubbed response.
292 | *
293 | * @return An `HTTPStubsResponse` describing the corresponding response to return by the stub
294 | *
295 | * @note For example you could use an error like `[NSError errorWithDomain:NSURLErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:nil]`
296 | */
297 | -(instancetype)initWithError:(NSError*)error NS_DESIGNATED_INITIALIZER;
298 |
299 | @end
300 |
301 | NS_ASSUME_NONNULL_END
302 |
--------------------------------------------------------------------------------
/Example/Pods/OHHTTPStubs/Sources/OHHTTPStubs/include/NSURLRequest+HTTPBodyTesting.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************************
2 | *
3 | * Copyright (c) 2016 Sebastian Hagedorn, Felix Lamouroux
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ***********************************************************************************/
24 |
25 | ////////////////////////////////////////////////////////////////////////////////
26 | #pragma mark - Imports
27 |
28 | #import
29 |
30 | // This category is only useful when NSURLSession is present
31 | #if defined(__IPHONE_7_0) || defined(__MAC_10_9)
32 |
33 | ////////////////////////////////////////////////////////////////////////////////
34 | #pragma mark - NSURLRequest+HTTPBodyTesting
35 |
36 | @interface NSURLRequest (HTTPBodyTesting)
37 | /**
38 | * Unfortunately, when sending POST requests (with a body) using NSURLSession,
39 | * by the time the request arrives at OHHTTPStubs, the HTTPBody of the
40 | * NSURLRequest has been reset to nil.
41 | *
42 | * You can use this method to retrieve the HTTPBody for testing and use it to
43 | * conditionally stub your requests.
44 | */
45 | - (NSData *)OHHTTPStubs_HTTPBody;
46 | @end
47 |
48 | #endif /* __IPHONE_7_0 || __MAC_10_9 */
49 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Hyperconnectivity.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.1.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Hyperconnectivity : NSObject
3 | @end
4 | @implementation PodsDummy_Hyperconnectivity
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double HyperconnectivityVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char HyperconnectivityVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "Combine" -framework "Network"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity.modulemap:
--------------------------------------------------------------------------------
1 | framework module Hyperconnectivity {
2 | umbrella header "Hyperconnectivity-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Hyperconnectivity/Hyperconnectivity.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "Combine" -framework "Network"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 9.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_OHHTTPStubs : NSObject
3 | @end
4 | @implementation PodsDummy_OHHTTPStubs
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "HTTPStubs.h"
14 | #import "HTTPStubsResponse.h"
15 | #import "Compatibility.h"
16 | #import "HTTPStubsResponse+JSON.h"
17 | #import "NSURLRequest+HTTPBodyTesting.h"
18 | #import "HTTPStubsPathHelpers.h"
19 | #import "Compatibility.h"
20 |
21 | FOUNDATION_EXPORT double OHHTTPStubsVersionNumber;
22 | FOUNDATION_EXPORT const unsigned char OHHTTPStubsVersionString[];
23 |
24 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Foundation"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/OHHTTPStubs
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap:
--------------------------------------------------------------------------------
1 | framework module OHHTTPStubs {
2 | umbrella header "OHHTTPStubs-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Foundation"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/OHHTTPStubs
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Hyperconnectivity
5 |
6 | Copyright (c) 2020 Ross Butler
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2020 Ross Butler
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | Hyperconnectivity
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_Hyperconnectivity_Example : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_Hyperconnectivity_Example
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 | BCSYMBOLMAP_DIR="BCSymbolMaps"
23 |
24 |
25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28 |
29 | # Copies and strips a vendored framework
30 | install_framework()
31 | {
32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 | local source="${BUILT_PRODUCTS_DIR}/$1"
34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 | elif [ -r "$1" ]; then
37 | local source="$1"
38 | fi
39 |
40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41 |
42 | if [ -L "${source}" ]; then
43 | echo "Symlinked..."
44 | source="$(readlink "${source}")"
45 | fi
46 |
47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 | echo "Installing $f"
51 | install_bcsymbolmap "$f" "$destination"
52 | rm "$f"
53 | done
54 | rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 | fi
56 |
57 | # Use filter instead of exclude so missing patterns don't throw errors.
58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60 |
61 | local basename
62 | basename="$(basename -s .framework "$1")"
63 | binary="${destination}/${basename}.framework/${basename}"
64 |
65 | if ! [ -r "$binary" ]; then
66 | binary="${destination}/${basename}"
67 | elif [ -L "${binary}" ]; then
68 | echo "Destination binary is symlinked..."
69 | dirname="$(dirname "${binary}")"
70 | binary="${dirname}/$(readlink "${binary}")"
71 | fi
72 |
73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 | strip_invalid_archs "$binary"
76 | fi
77 |
78 | # Resign the code if required by the build settings to avoid unstable apps
79 | code_sign_if_enabled "${destination}/$(basename "$1")"
80 |
81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 | local swift_runtime_libs
84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 | for lib in $swift_runtime_libs; do
86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 | code_sign_if_enabled "${destination}/${lib}"
89 | done
90 | fi
91 | }
92 | # Copies and strips a vendored dSYM
93 | install_dsym() {
94 | local source="$1"
95 | warn_missing_arch=${2:-true}
96 | if [ -r "$source" ]; then
97 | # Copy the dSYM into the targets temp dir.
98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100 |
101 | local basename
102 | basename="$(basename -s .dSYM "$source")"
103 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105 |
106 | # Strip invalid architectures from the dSYM.
107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 | strip_invalid_archs "$binary" "$warn_missing_arch"
109 | fi
110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 | # Move the stripped file into its final destination.
112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 | else
115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 | fi
119 | fi
120 | }
121 |
122 | # Used as a return value for each invocation of `strip_invalid_archs` function.
123 | STRIP_BINARY_RETVAL=0
124 |
125 | # Strip invalid architectures
126 | strip_invalid_archs() {
127 | binary="$1"
128 | warn_missing_arch=${2:-true}
129 | # Get architectures for current target binary
130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 | # Intersect them with the architectures we are building for
132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 | # If there are no archs supported by this binary then warn the user
134 | if [[ -z "$intersected_archs" ]]; then
135 | if [[ "$warn_missing_arch" == "true" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | fi
138 | STRIP_BINARY_RETVAL=1
139 | return
140 | fi
141 | stripped=""
142 | for arch in $binary_archs; do
143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 | # Strip non-valid architectures in-place
145 | lipo -remove "$arch" -output "$binary" "$binary"
146 | stripped="$stripped $arch"
147 | fi
148 | done
149 | if [[ "$stripped" ]]; then
150 | echo "Stripped $binary of architectures:$stripped"
151 | fi
152 | STRIP_BINARY_RETVAL=0
153 | }
154 |
155 | # Copies the bcsymbolmap files of a vendored framework
156 | install_bcsymbolmap() {
157 | local bcsymbolmap_path="$1"
158 | local destination="${BUILT_PRODUCTS_DIR}"
159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 | }
162 |
163 | # Signs a framework with the provided identity
164 | code_sign_if_enabled() {
165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 | # Use the current code_sign_identity
167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169 |
170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 | code_sign_cmd="$code_sign_cmd &"
172 | fi
173 | echo "$code_sign_cmd"
174 | eval "$code_sign_cmd"
175 | fi
176 | }
177 |
178 | if [[ "$CONFIGURATION" == "Debug" ]]; then
179 | install_framework "${BUILT_PRODUCTS_DIR}/Hyperconnectivity/Hyperconnectivity.framework"
180 | fi
181 | if [[ "$CONFIGURATION" == "Release" ]]; then
182 | install_framework "${BUILT_PRODUCTS_DIR}/Hyperconnectivity/Hyperconnectivity.framework"
183 | fi
184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 | wait
186 | fi
187 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_Hyperconnectivity_ExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_Hyperconnectivity_ExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity/Hyperconnectivity.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Combine" -framework "Hyperconnectivity" -framework "Network"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_Hyperconnectivity_Example {
2 | umbrella header "Pods-Hyperconnectivity_Example-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Example/Pods-Hyperconnectivity_Example.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity/Hyperconnectivity.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Combine" -framework "Hyperconnectivity" -framework "Network"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## OHHTTPStubs
5 |
6 | - MIT LICENSE -
7 |
8 | Copyright (c) 2012 Olivier Halligon
9 |
10 | 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:
11 |
12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 |
14 | 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.
15 | Generated by CocoaPods - https://cocoapods.org
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | - MIT LICENSE -
18 |
19 | Copyright (c) 2012 Olivier Halligon
20 |
21 | 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:
22 |
23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
24 |
25 | 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.
26 | License
27 | MIT
28 | Title
29 | OHHTTPStubs
30 | Type
31 | PSGroupSpecifier
32 |
33 |
34 | FooterText
35 | Generated by CocoaPods - https://cocoapods.org
36 | Title
37 |
38 | Type
39 | PSGroupSpecifier
40 |
41 |
42 | StringsTable
43 | Acknowledgements
44 | Title
45 | Acknowledgements
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_Hyperconnectivity_Tests : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_Hyperconnectivity_Tests
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 | BCSYMBOLMAP_DIR="BCSymbolMaps"
23 |
24 |
25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28 |
29 | # Copies and strips a vendored framework
30 | install_framework()
31 | {
32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 | local source="${BUILT_PRODUCTS_DIR}/$1"
34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 | elif [ -r "$1" ]; then
37 | local source="$1"
38 | fi
39 |
40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41 |
42 | if [ -L "${source}" ]; then
43 | echo "Symlinked..."
44 | source="$(readlink "${source}")"
45 | fi
46 |
47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 | echo "Installing $f"
51 | install_bcsymbolmap "$f" "$destination"
52 | rm "$f"
53 | done
54 | rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 | fi
56 |
57 | # Use filter instead of exclude so missing patterns don't throw errors.
58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60 |
61 | local basename
62 | basename="$(basename -s .framework "$1")"
63 | binary="${destination}/${basename}.framework/${basename}"
64 |
65 | if ! [ -r "$binary" ]; then
66 | binary="${destination}/${basename}"
67 | elif [ -L "${binary}" ]; then
68 | echo "Destination binary is symlinked..."
69 | dirname="$(dirname "${binary}")"
70 | binary="${dirname}/$(readlink "${binary}")"
71 | fi
72 |
73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 | strip_invalid_archs "$binary"
76 | fi
77 |
78 | # Resign the code if required by the build settings to avoid unstable apps
79 | code_sign_if_enabled "${destination}/$(basename "$1")"
80 |
81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 | local swift_runtime_libs
84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 | for lib in $swift_runtime_libs; do
86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 | code_sign_if_enabled "${destination}/${lib}"
89 | done
90 | fi
91 | }
92 | # Copies and strips a vendored dSYM
93 | install_dsym() {
94 | local source="$1"
95 | warn_missing_arch=${2:-true}
96 | if [ -r "$source" ]; then
97 | # Copy the dSYM into the targets temp dir.
98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100 |
101 | local basename
102 | basename="$(basename -s .dSYM "$source")"
103 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105 |
106 | # Strip invalid architectures from the dSYM.
107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 | strip_invalid_archs "$binary" "$warn_missing_arch"
109 | fi
110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 | # Move the stripped file into its final destination.
112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 | else
115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 | fi
119 | fi
120 | }
121 |
122 | # Used as a return value for each invocation of `strip_invalid_archs` function.
123 | STRIP_BINARY_RETVAL=0
124 |
125 | # Strip invalid architectures
126 | strip_invalid_archs() {
127 | binary="$1"
128 | warn_missing_arch=${2:-true}
129 | # Get architectures for current target binary
130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 | # Intersect them with the architectures we are building for
132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 | # If there are no archs supported by this binary then warn the user
134 | if [[ -z "$intersected_archs" ]]; then
135 | if [[ "$warn_missing_arch" == "true" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | fi
138 | STRIP_BINARY_RETVAL=1
139 | return
140 | fi
141 | stripped=""
142 | for arch in $binary_archs; do
143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 | # Strip non-valid architectures in-place
145 | lipo -remove "$arch" -output "$binary" "$binary"
146 | stripped="$stripped $arch"
147 | fi
148 | done
149 | if [[ "$stripped" ]]; then
150 | echo "Stripped $binary of architectures:$stripped"
151 | fi
152 | STRIP_BINARY_RETVAL=0
153 | }
154 |
155 | # Copies the bcsymbolmap files of a vendored framework
156 | install_bcsymbolmap() {
157 | local bcsymbolmap_path="$1"
158 | local destination="${BUILT_PRODUCTS_DIR}"
159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 | }
162 |
163 | # Signs a framework with the provided identity
164 | code_sign_if_enabled() {
165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 | # Use the current code_sign_identity
167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169 |
170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 | code_sign_cmd="$code_sign_cmd &"
172 | fi
173 | echo "$code_sign_cmd"
174 | eval "$code_sign_cmd"
175 | fi
176 | }
177 |
178 | if [[ "$CONFIGURATION" == "Debug" ]]; then
179 | install_framework "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework"
180 | fi
181 | if [[ "$CONFIGURATION" == "Release" ]]; then
182 | install_framework "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework"
183 | fi
184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 | wait
186 | fi
187 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_Hyperconnectivity_TestsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_Hyperconnectivity_TestsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity" "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity/Hyperconnectivity.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Combine" -framework "Foundation" -framework "Hyperconnectivity" -framework "Network" -framework "OHHTTPStubs"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_Hyperconnectivity_Tests {
2 | umbrella header "Pods-Hyperconnectivity_Tests-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Hyperconnectivity_Tests/Pods-Hyperconnectivity_Tests.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity" "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Hyperconnectivity/Hyperconnectivity.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Combine" -framework "Foundation" -framework "Hyperconnectivity" -framework "Network" -framework "OHHTTPStubs"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Tests/ConnectionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectionTests.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 10/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Network
11 | import XCTest
12 | @testable import Hyperconnectivity
13 |
14 | class ConnectionTests: XCTestCase {
15 |
16 | func testIfPathIsWiredEthernetThenConnectionIsEthernet() {
17 | let path = MockPath(interfaceType: .wiredEthernet)
18 | let sut = Connection(path)
19 | XCTAssertEqual(sut, .ethernet)
20 | }
21 |
22 | func testIfPathIsWiFiThenConnectionIsWiFi() {
23 | let path = MockPath(interfaceType: .wifi)
24 | let sut = Connection(path)
25 | XCTAssertEqual(sut, .wifi)
26 | }
27 |
28 | func testIfPathIsCellularThenConnectionIsCellular() {
29 | let path = MockPath(interfaceType: .cellular)
30 | let sut = Connection(path)
31 | XCTAssertEqual(sut, .cellular)
32 | }
33 |
34 | func testIfPathIsWiFiThenConnectionIsOther() {
35 | let path = MockPath(interfaceType: .other)
36 | let sut = Connection(path)
37 | XCTAssertEqual(sut, .other)
38 | }
39 |
40 | func testIfPathIsLoopbackThenConnectionIsLoopback() {
41 | let path = MockPath(interfaceType: .loopback)
42 | let sut = Connection(path)
43 | XCTAssertEqual(sut, .loopback)
44 | }
45 |
46 | func testIfPathIsNilThenConnectionIsDisconnected() {
47 | let path = MockPath(interfaceType: nil)
48 | let sut = Connection(path)
49 | XCTAssertEqual(sut, .disconnected)
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/Example/Tests/ConnectivityPublisherTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectivityPublisherTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Combine
10 | import Foundation
11 | import OHHTTPStubs
12 | #if canImport(OHHTTPStubsSwift)
13 | import OHHTTPStubsSwift
14 | #endif
15 | import XCTest
16 | @testable import Hyperconnectivity
17 |
18 | class ConnectivityPublisherTests: XCTestCase {
19 | private var cancellable: AnyCancellable?
20 | private let timeout: TimeInterval = 5.0
21 |
22 | override func tearDown() {
23 | super.tearDown()
24 | HTTPStubs.removeAllStubs()
25 | cancellable = nil
26 | }
27 |
28 | private func stubHost(_ host: String, withHTMLFrom fileName: String) throws {
29 | #if SWIFT_PACKAGE
30 | let bundle = Bundle.module
31 | #else
32 | let bundle = Bundle(for: type(of: self))
33 | #endif
34 | let fileURL = bundle.url(
35 | forResource: (fileName as NSString).deletingPathExtension,
36 | withExtension: (fileName as NSString).pathExtension
37 | )
38 | let stubPath = try XCTUnwrap(fileURL?.relativePath)
39 | stub(condition: isHost(host)) { _ in
40 | return fixture(filePath: stubPath, headers: ["Content-Type": "text/html"])
41 | }
42 | }
43 |
44 | func testSubscriberInvokedOnSuccessfulConnectivityCheck() throws {
45 | try stubHost("captive.apple.com", withHTMLFrom: "string-contains-response.html")
46 | try stubHost("www.apple.com", withHTMLFrom: "string-contains-response.html")
47 | let expectation = XCTestExpectation(description: "Connectivity check succeeds")
48 | cancellable = Hyperconnectivity.Publisher().sink(receiveCompletion: { _ in
49 | }, receiveValue: { result in
50 | XCTAssert(result.state == .wifiWithInternet || result.state == .ethernetWithInternet)
51 | expectation.fulfill()
52 | })
53 | wait(for: [expectation], timeout: timeout)
54 | }
55 |
56 | func testSubscriberInvokedOnFailedConnectivityCheck() throws {
57 | try stubHost("captive.apple.com", withHTMLFrom: "failure-response.html")
58 | try stubHost("www.apple.com", withHTMLFrom: "failure-response.html")
59 | let expectation = XCTestExpectation(description: "Connectivity check fails")
60 | cancellable = Hyperconnectivity.Publisher().sink(receiveCompletion: { _ in
61 | }, receiveValue: { result in
62 | XCTAssert(result.state == .wifiWithoutInternet || result.state == .ethernetWithoutInternet)
63 | expectation.fulfill()
64 | })
65 | wait(for: [expectation], timeout: timeout)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Example/Tests/ConnectivityStateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectivityStateTests.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 09/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import Hyperconnectivity
12 |
13 | class ConnectivityStateTests: XCTestCase {
14 |
15 | func testConnectionIsCellularAndIsConnected() {
16 | let sut = ConnectivityState(connection: .cellular, isConnected: true)
17 | XCTAssertEqual(sut, .cellularWithInternet)
18 | }
19 |
20 | func testConnectionIsCellularAndIsNotConnected() {
21 | let sut = ConnectivityState(connection: .cellular, isConnected: false)
22 | XCTAssertEqual(sut, .cellularWithoutInternet)
23 | }
24 |
25 | func testConnectionIsDisconnectedAndIsConnected() {
26 | let sut = ConnectivityState(connection: .disconnected, isConnected: true)
27 | XCTAssertEqual(sut, .disconnected)
28 | }
29 |
30 | func testConnectionIsDisconnectedAndIsNotConnected() {
31 | let sut = ConnectivityState(connection: .disconnected, isConnected: false)
32 | XCTAssertEqual(sut, .disconnected)
33 | }
34 |
35 | func testConnectionIsEthernetAndIsConnected() {
36 | let sut = ConnectivityState(connection: .ethernet, isConnected: true)
37 | XCTAssertEqual(sut, .ethernetWithInternet)
38 | }
39 |
40 | func testConnectionIsEthernetAndIsNotConnected() {
41 | let sut = ConnectivityState(connection: .ethernet, isConnected: false)
42 | XCTAssertEqual(sut, .ethernetWithoutInternet)
43 | }
44 |
45 | func testConnectionIsLoopbackAndIsConnected() {
46 | let sut = ConnectivityState(connection: .loopback, isConnected: true)
47 | XCTAssertEqual(sut, .loopback)
48 | }
49 |
50 | func testConnectionIsLoopbackAndIsNotConnected() {
51 | let sut = ConnectivityState(connection: .loopback, isConnected: false)
52 | XCTAssertEqual(sut, .loopback)
53 | }
54 |
55 | func testConnectionIsOtherAndIsConnected() {
56 | let sut = ConnectivityState(connection: .other, isConnected: true)
57 | XCTAssertEqual(sut, .otherWithInternet)
58 | }
59 |
60 | func testConnectionIsOtherAndIsNotConnected() {
61 | let sut = ConnectivityState(connection: .other, isConnected: false)
62 | XCTAssertEqual(sut, .otherWithoutInternet)
63 | }
64 |
65 | func testConnectionIsWiFiAndIsConnected() {
66 | let sut = ConnectivityState(connection: .wifi, isConnected: true)
67 | XCTAssertEqual(sut, .wifiWithInternet)
68 | }
69 |
70 | func testConnectionIsWiFiAndIsNotConnected() {
71 | let sut = ConnectivityState(connection: .wifi, isConnected: false)
72 | XCTAssertEqual(sut, .wifiWithoutInternet)
73 | }
74 |
75 | func testDescriptionForCellularWithInternetIsCorrect() {
76 | let sut = ConnectivityState.cellularWithInternet
77 | XCTAssertEqual(sut.description, "Cellular with Internet connectivity")
78 | }
79 |
80 | func testDescriptionForCellularWithoutInternetIsCorrect() {
81 | let sut = ConnectivityState.cellularWithoutInternet
82 | XCTAssertEqual(sut.description, "Cellular without Internet connectivity")
83 | }
84 |
85 | func testDescriptionForDisconnectedIsCorrect() {
86 | let sut = ConnectivityState.disconnected
87 | XCTAssertEqual(sut.description, "Disconnected")
88 | }
89 |
90 | func testDescriptionForEthernetWithInternetIsCorrect() {
91 | let sut = ConnectivityState.ethernetWithInternet
92 | XCTAssertEqual(sut.description, "Ethernet with Internet connectivity")
93 | }
94 |
95 | func testDescriptionForethernetWithoutInternetIsCorrect() {
96 | let sut = ConnectivityState.ethernetWithoutInternet
97 | XCTAssertEqual(sut.description, "Ethernet without Internet connectivity")
98 | }
99 |
100 | func testDescriptionForLoopbackIsCorrect() {
101 | let sut = ConnectivityState.loopback
102 | XCTAssertEqual(sut.description, "Loopback")
103 | }
104 |
105 | func testDescriptionForOtherWithInternetIsCorrect() {
106 | let sut = ConnectivityState.otherWithInternet
107 | XCTAssertEqual(sut.description, "Other with Internet connectivity")
108 | }
109 |
110 | func testDescriptionForOtherWithoutInternetIsCorrect() {
111 | let sut = ConnectivityState.otherWithoutInternet
112 | XCTAssertEqual(sut.description, "Other without Internet connectivity")
113 | }
114 |
115 | func testDescriptionForWiFiWithInternetIsCorrect() {
116 | let sut = ConnectivityState.wifiWithInternet
117 | XCTAssertEqual(sut.description, "Wi-Fi with Internet connectivity")
118 | }
119 |
120 | func testDescriptionForWiFiWithoutInternetIsCorrect() {
121 | let sut = ConnectivityState.wifiWithoutInternet
122 | XCTAssertEqual(sut.description, "Wi-Fi without Internet connectivity")
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/Example/Tests/ConnectivitySubscriptionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectivitySubscriptionTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 15/05/2020.
6 | // Copyright © 2020 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 | import Network
12 | import XCTest
13 | @testable import Hyperconnectivity
14 |
15 | class ConnectivitySubscriptionTests: XCTestCase {
16 | private let timeout: TimeInterval = 5.0
17 |
18 | private func sut(subscriber: Subscribers.Sink? = nil, connectivity: Connectivity? = nil) -> ConnectivitySubscription> {
19 | let mockSubscriber = subscriber ?? Subscribers.Sink(receiveCompletion: { _ in }) { _ in }
20 | let mockConfiguration = Hyperconnectivity.Configuration()
21 | return ConnectivitySubscription(
22 | configuration: mockConfiguration,
23 | connectivity: connectivity,
24 | subscriber: mockSubscriber
25 | )
26 | }
27 |
28 | func testNotifierStartedWhenSubscriptionCreated() {
29 | let mockConfiguration = Hyperconnectivity.Configuration()
30 | let mockConnectivity = MockConnectivity(configuration: mockConfiguration)
31 | _ = sut(connectivity: mockConnectivity)
32 | XCTAssertTrue(mockConnectivity.startNotifierInvoked)
33 | }
34 |
35 | func testNotifierStoppedWhenSubscriptionCancelled() {
36 | let mockConfiguration = Hyperconnectivity.Configuration()
37 | let mockConnectivity = MockConnectivity(configuration: mockConfiguration)
38 | let sut = self.sut(connectivity: mockConnectivity)
39 | sut.cancel()
40 | XCTAssertTrue(mockConnectivity.stopNotifierInvoked)
41 | }
42 |
43 | func testNotificationSentWhenSubscriptionCreated() {
44 | expectation(
45 | forNotification: .ConnectivityDidStart,
46 | object: nil,
47 | handler: nil
48 | )
49 | _ = sut()
50 | waitForExpectations(timeout: timeout, handler: nil)
51 | }
52 |
53 | func testNotificationSentWhenSubscriptionCancelled() {
54 | expectation(
55 | forNotification: .ConnectivityDidFinish,
56 | object: nil,
57 | handler: nil
58 | )
59 | let sut = self.sut()
60 | sut.cancel()
61 | waitForExpectations(timeout: timeout, handler: nil)
62 | }
63 |
64 | func testSubscriberCompletesWhenSubscriptionCancelled() {
65 | let connectivityFinishedExpectation = expectation(description: "Connectivity finished")
66 | let mockSubscriber = Subscribers.Sink(receiveCompletion: { _ in
67 | connectivityFinishedExpectation.fulfill()
68 | }) { _ in}
69 | let sut = self.sut(subscriber: mockSubscriber)
70 | sut.cancel()
71 | waitForExpectations(timeout: timeout, handler: nil)
72 | }
73 |
74 | func testSubscriberNotifiedWhenConnectivityChanged() {
75 | let mockConfiguration = Hyperconnectivity.Configuration()
76 | let connectivityChangedExpectation = expectation(description: "Connectivity changed")
77 | let mockSubscriber = Subscribers.Sink(receiveCompletion: { _ in }) { _ in
78 | connectivityChangedExpectation.fulfill()
79 | }
80 | let mockConnectivity = MockConnectivity(configuration: mockConfiguration)
81 | _ = sut(subscriber: mockSubscriber, connectivity: mockConnectivity)
82 | let mockPath = MockPath(interfaceType: .wiredEthernet)
83 | let mockResult = ConnectivityResult(path: mockPath, successThreshold: Percentage(100.0), totalChecks: 0)
84 | mockConnectivity.connectivityChanged?(mockResult)
85 | waitForExpectations(timeout: timeout, handler: nil)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/MockConnectivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockConnectivity.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | @testable import Hyperconnectivity
11 |
12 | class MockConnectivity: Connectivity {
13 | var connectivityChanged: Hyperconnectivity.ConnectivityChanged?
14 | var initInvoked = false
15 | var startNotifierInvoked = false
16 | var stopNotifierInvoked = false
17 |
18 | required init(configuration: Hyperconnectivity.Configuration) {
19 | initInvoked = true
20 | }
21 |
22 | func startNotifier() {
23 | startNotifierInvoked = true
24 | }
25 |
26 | func stopNotifier() {
27 | stopNotifierInvoked = true
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Example/Tests/MockPath.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockPath.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Network
11 | @testable import Hyperconnectivity
12 |
13 | struct MockPath: Path {
14 | var isExpensive: Bool = false
15 | private let interfaceType: NWInterface.InterfaceType?
16 |
17 | init(interfaceType: NWInterface.InterfaceType?) {
18 | self.interfaceType = interfaceType
19 | }
20 |
21 | func usesInterfaceType(_ type: NWInterface.InterfaceType) -> Bool {
22 | return interfaceType == type
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Example/Tests/NonCachingURLSessionConfigurationFactoryTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NonCachingURLSessionConfigurationFactoryTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 20/03/2022.
6 | // Copyright © 2022 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | @testable import Hyperconnectivity
11 | import XCTest
12 |
13 | class NonCachingURLSessionConfigurationFactoryTests: XCTestCase {
14 | /// Tests that given a `URLSessionConfiguration` object with a response cache set, the factory will return a `URLSessionConfiguration` object which does not cache.
15 | func testResponseCachingIsDisabled() {
16 | let sut = NonCachingURLSessionConfigurationFactory()
17 | let originalURLSessionConfiguration = URLSessionConfiguration.default
18 | XCTAssertNotNil(originalURLSessionConfiguration.urlCache)
19 | let newURLSessionConfiguration = sut.urlSessionConfiguration(from: originalURLSessionConfiguration)
20 | XCTAssertNil(newURLSessionConfiguration.urlCache, "URL cache should be nil.")
21 | }
22 |
23 | /// Tests that the `URLSessionConfiguration` passed as input to the factory is copied i.e. the output of the factory is a different object.
24 | func testThatFactoryProducesACopy() {
25 | let sut = NonCachingURLSessionConfigurationFactory()
26 | let originalURLSessionConfiguration = URLSessionConfiguration.default
27 | let newURLSessionConfiguration = sut.urlSessionConfiguration(from: originalURLSessionConfiguration)
28 | XCTAssertFalse(originalURLSessionConfiguration === newURLSessionConfiguration)
29 | }
30 |
31 | /// Tests that given a `URLSessionConfiguration` object passed as input to the factory, the request caching policy of the output ignores the local cache.
32 | func testRequestCachePolicyIgnoresLocalCache() {
33 | let sut = NonCachingURLSessionConfigurationFactory()
34 | let originalURLSessionConfiguration = URLSessionConfiguration.default
35 | XCTAssertEqual(originalURLSessionConfiguration.requestCachePolicy, .useProtocolCachePolicy)
36 | let newURLSessionConfiguration = sut.urlSessionConfiguration(from: originalURLSessionConfiguration)
37 | XCTAssertEqual(newURLSessionConfiguration.requestCachePolicy, .reloadIgnoringLocalCacheData)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Example/Tests/PercentageTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PercentageTests.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 09/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Hyperconnectivity
11 |
12 | class PercentageTests: XCTestCase {
13 |
14 | func testMidRangeValueApplied() {
15 | let sut = Percentage(50.0)
16 | XCTAssertEqual(sut.value, 50.0)
17 | }
18 |
19 | func testLowerBoundaryValueApplied() {
20 | let sut = Percentage(0.0)
21 | XCTAssertEqual(sut.value, 0.0)
22 | }
23 |
24 | func testUpperBoundaryValueApplied() {
25 | let sut = Percentage(100.0)
26 | XCTAssertEqual(sut.value, 100.0)
27 | }
28 |
29 | func testOutOfLowerBoundValueNotApplied() {
30 | let sut = Percentage(-0.1)
31 | XCTAssertEqual(sut.value, 0.0)
32 | }
33 |
34 | func testOutOfUpperBoundValueNotApplied() {
35 | let sut = Percentage(100.1)
36 | XCTAssertEqual(sut.value, 100.0)
37 | }
38 |
39 | func testPercentageCalculatedWithMidRangeUIntValues() {
40 | let sut = Percentage(UInt(2), outOf: UInt(10))
41 | XCTAssertEqual(sut.value, 20.0)
42 | }
43 |
44 | func testPercentageCalculatedWithLowerBoundaryUIntValues() {
45 | let sut = Percentage(UInt(0), outOf: UInt(1))
46 | XCTAssertEqual(sut.value, 0.0)
47 | }
48 |
49 | func testPercentageCalculatedIsZeroWhenDivisorIsZero() {
50 | let sut = Percentage(UInt(1), outOf: UInt(0))
51 | XCTAssertEqual(sut.value, 0.0)
52 | }
53 |
54 | func testPercentageNotLessThanSameValue() {
55 | XCTAssertFalse(Percentage(0.0) < Percentage(0.0))
56 | }
57 |
58 | func testPercentageIsLessThanGreaterValue() {
59 | XCTAssertTrue(Percentage(0.0) < Percentage(0.1))
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Example/Tests/ReachabilityPublisherTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReachabilityPublisherTests.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Combine
10 | import Foundation
11 | #if canImport(OHHTTPStubsSwift)
12 | import OHHTTPStubsSwift
13 | #endif
14 | import XCTest
15 | @testable import Hyperconnectivity
16 |
17 | class ReachabilityPublisherTests: XCTestCase {
18 | private var cancellable: AnyCancellable?
19 | private let timeout: TimeInterval = 5.0
20 |
21 | func testSubscriberInvokedOnSuccessfulReachabilityCheck() throws {
22 | let expectation = XCTestExpectation(description: "Reachability check succeeds")
23 | cancellable = Publishers.Reachability().sink(receiveCompletion: { _ in
24 | }, receiveValue: { result in
25 | XCTAssert(result.connection == .wifi || result.connection == .ethernet)
26 | XCTAssertTrue(result.isReachable)
27 | expectation.fulfill()
28 | })
29 | wait(for: [expectation], timeout: timeout)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Example/Tests/ResponseContainsStringValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseContainsStringValidatorTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import OHHTTPStubs
11 | #if canImport(OHHTTPStubsSwift)
12 | import OHHTTPStubsSwift
13 | #endif
14 | import XCTest
15 | @testable import Hyperconnectivity
16 |
17 | class ResponseContainsStringValidatorTests: XCTestCase {
18 | private let timeout: TimeInterval = 5.0
19 |
20 | override func tearDown() {
21 | super.tearDown()
22 | HTTPStubs.removeAllStubs()
23 | }
24 |
25 | private func stubHost(_ host: String, withHTMLFrom fileName: String) throws {
26 | #if SWIFT_PACKAGE
27 | let bundle = Bundle.module
28 | #else
29 | let bundle = Bundle(for: type(of: self))
30 | #endif
31 | let fileURL = bundle.url(
32 | forResource: (fileName as NSString).deletingPathExtension,
33 | withExtension: (fileName as NSString).pathExtension
34 | )
35 | let stubPath = try XCTUnwrap(fileURL?.relativePath)
36 | stub(condition: isHost(host)) { _ in
37 | return fixture(filePath: stubPath, headers: ["Content-Type": "text/html"])
38 | }
39 | }
40 |
41 | /// Test response is valid when the response string contains the expected response.
42 | func testContainsExpectedResponseString() throws {
43 | try stubHost("www.apple.com", withHTMLFrom: "string-contains-response.html")
44 | let expectation = XCTestExpectation(description: "Connectivity check succeeds")
45 | let config = Hyperconnectivity.Configuration(responseValidator: ResponseContainsStringValidator(expectedResponse: "Success"))
46 | let connectivity = Hyperconnectivity(configuration: config)
47 | let connectivityChanged: (ConnectivityResult) -> Void = { result in
48 | XCTAssert(result.state == .wifiWithInternet || result.state == .ethernetWithInternet)
49 | expectation.fulfill()
50 | }
51 | connectivity.connectivityChanged = connectivityChanged
52 | connectivity.startNotifier()
53 | wait(for: [expectation], timeout: timeout)
54 | connectivity.stopNotifier()
55 | }
56 |
57 | /// Test response is valid when the response string does not contain the expected response.
58 | func testDoesNotContainExpectedResponseString() throws {
59 | try stubHost("www.apple.com", withHTMLFrom: "string-contains-response.html")
60 | let expectation = XCTestExpectation(description: "Connectivity check succeeds")
61 | let config = Hyperconnectivity.Configuration(responseValidator: ResponseContainsStringValidator(expectedResponse: "Failure"))
62 | let connectivity = Hyperconnectivity(configuration: config)
63 | let connectivityChanged: (ConnectivityResult) -> Void = { result in
64 | XCTAssert(result.state == .wifiWithoutInternet || result.state == .ethernetWithoutInternet)
65 | expectation.fulfill()
66 | }
67 | connectivity.connectivityChanged = connectivityChanged
68 | connectivity.startNotifier()
69 | wait(for: [expectation], timeout: timeout)
70 | connectivity.stopNotifier()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Example/Tests/ResponseRegExValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseRegExValidatorTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import Hyperconnectivity
12 |
13 | class ResponseRegExValidatorTests: XCTestCase {
14 | func testRegexStringValidation() throws {
15 | try checkValid(string: "test1234", matchedBy: "test[0-9]+", expectedResult: true)
16 | try checkValid(string: "testa1234", matchedBy: "test[0-9]+", expectedResult: false)
17 | }
18 |
19 | private func checkValid(
20 | string: String,
21 | matchedBy regEx: String,
22 | expectedResult: Bool,
23 | file: StaticString = #file,
24 | line: UInt = #line
25 | ) throws {
26 | let validator = ResponseRegExValidator(regEx: regEx)
27 | let data = try XCTUnwrap(string.data(using: .utf8))
28 | let url = try XCTUnwrap(URL(string: "https://example.com"))
29 | let response = URLResponse(url: url, mimeType: nil, expectedContentLength: data.count, textEncodingName: nil)
30 | let result = validator.isResponseValid(response, data: data)
31 | let expectedResultStr = expectedResult ? "match" : "not match"
32 | let message = "Expected \"\(string)\" to \(expectedResultStr) \(regEx) via regex"
33 | XCTAssertEqual(result, expectedResult, message, file: file, line: line)
34 | }
35 |
36 | func testResponseInvalidWhenDataIsNil() throws {
37 | let regEx = "test[0-9]+"
38 | let validator = ResponseRegExValidator(regEx: regEx)
39 | let url = try XCTUnwrap(URL(string: "https://example.com"))
40 | let data = try XCTUnwrap("".data(using: .utf8))
41 | let response = URLResponse(url: url, mimeType: nil, expectedContentLength: 0, textEncodingName: nil)
42 | let responseValid = validator.isResponseValid(response, data: data)
43 | XCTAssertFalse(responseValid)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Example/Tests/ResponseStringEqualityValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseStringValidatorTests.swift
3 | // Hyperconnectivity_Tests
4 | //
5 | // Created by Ross Butler on 17/05/2020.
6 | // Copyright © 2020 Ross Butler. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import OHHTTPStubs
11 | #if canImport(OHHTTPStubsSwift)
12 | import OHHTTPStubsSwift
13 | #endif
14 | import XCTest
15 | @testable import Hyperconnectivity
16 |
17 | class ResponseStringEqualityValidatorTests: XCTestCase {
18 | private let timeout: TimeInterval = 5.0
19 |
20 | override func tearDown() {
21 | super.tearDown()
22 | HTTPStubs.removeAllStubs()
23 | }
24 |
25 | private func stubHost(_ host: String, withHTMLFrom fileName: String) throws {
26 | #if SWIFT_PACKAGE
27 | let bundle = Bundle.module
28 | #else
29 | let bundle = Bundle(for: type(of: self))
30 | #endif
31 | let fileURL = bundle.url(
32 | forResource: (fileName as NSString).deletingPathExtension,
33 | withExtension: (fileName as NSString).pathExtension
34 | )
35 | let stubPath = try XCTUnwrap(fileURL?.relativePath)
36 | stub(condition: isHost(host)) { _ in
37 | return fixture(filePath: stubPath, headers: ["Content-Type": "text/html"])
38 | }
39 | }
40 |
41 | /// Test response is valid when the response string is equal to the expected response.
42 | func testEqualsExpectedResponseString() throws {
43 | try stubHost("www.apple.com", withHTMLFrom: "string-equality-response.html")
44 | let expectation = XCTestExpectation(description: "Connectivity check succeeds")
45 | let config = Hyperconnectivity.Configuration(responseValidator: ResponseStringEqualityValidator(expectedResponse: "Success"))
46 | let connectivity = Hyperconnectivity(configuration: config)
47 | let connectivityChanged: (ConnectivityResult) -> Void = { result in
48 | XCTAssert(result.state == .wifiWithInternet || result.state == .ethernetWithInternet)
49 | expectation.fulfill()
50 | }
51 | connectivity.connectivityChanged = connectivityChanged
52 | connectivity.startNotifier()
53 | wait(for: [expectation], timeout: timeout)
54 | connectivity.stopNotifier()
55 | }
56 |
57 | /// Test response is valid when the response string is equal to the expected response.
58 | func testEqualsExpectedSpecifiedResponseString() throws {
59 | try stubHost("www.apple.com", withHTMLFrom: "string-equality-response.html")
60 | let expectation = XCTestExpectation(description: "Connectivity check succeeds")
61 | let config = Hyperconnectivity.Configuration(responseValidator: ResponseStringEqualityValidator(expectedResponse: "Success"))
62 | let connectivity = Hyperconnectivity(configuration: config)
63 | let connectivityChanged: (ConnectivityResult) -> Void = { result in
64 | XCTAssert(result.state == .wifiWithInternet || result.state == .ethernetWithInternet)
65 | expectation.fulfill()
66 | }
67 | connectivity.connectivityChanged = connectivityChanged
68 | connectivity.startNotifier()
69 | wait(for: [expectation], timeout: timeout)
70 | connectivity.stopNotifier()
71 | }
72 |
73 | /// Test response is invalid when the response string is not equal to the expected response.
74 | func testNotEqualsExpectedResponseString() throws {
75 | try stubHost("www.apple.com", withHTMLFrom: "string-contains-response.html")
76 | let expectation = XCTestExpectation(description: "Connectivity check fails")
77 | let config = Hyperconnectivity.Configuration(responseValidator: ResponseStringEqualityValidator(expectedResponse: "Success"))
78 | let connectivity = Hyperconnectivity(configuration: config)
79 | let connectivityChanged: (ConnectivityResult) -> Void = { result in
80 | XCTAssert(result.state == .wifiWithoutInternet || result.state == .ethernetWithoutInternet)
81 | expectation.fulfill()
82 | }
83 | connectivity.connectivityChanged = connectivityChanged
84 | connectivity.startNotifier()
85 | wait(for: [expectation], timeout: timeout)
86 | connectivity.stopNotifier()
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Example/Tests/failure-response.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Example/Tests/string-contains-response.html:
--------------------------------------------------------------------------------
1 |
2 | Successful
3 |
4 |
--------------------------------------------------------------------------------
/Example/Tests/string-equality-response.html:
--------------------------------------------------------------------------------
1 | Success
2 |
--------------------------------------------------------------------------------
/Hyperconnectivity.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'Hyperconnectivity'
3 | s.version = '1.1.1'
4 | s.swift_version = '5.0'
5 | s.summary = 'Modern replacement for Apple\'s Reachability written in Swift and made elegant using Combine'
6 | s.description = <<-DESC
7 | Hyperconnectivity provides Internet connectivity and captive portal detection in Swift using Combine.
8 | DESC
9 | s.homepage = 'https://github.com/rwbutler/Hyperconnectivity'
10 | s.license = { :type => 'MIT', :file => 'LICENSE' }
11 | s.author = { 'Ross Butler' => 'github@rwbutler.com' }
12 | s.source = { :git => 'https://github.com/rwbutler/Hyperconnectivity.git', :tag => s.version.to_s }
13 | s.social_media_url = 'https://twitter.com/ross_w_butler'
14 | s.ios.deployment_target = '13.0'
15 | s.frameworks = 'Combine', 'Network'
16 | s.source_files = 'Hyperconnectivity/Classes/**/*'
17 | end
18 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwbutler/Hyperconnectivity/0503595f9ab5bfdef6c06c2d8c2712cb50213259/Hyperconnectivity/Assets/.gitkeep
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwbutler/Hyperconnectivity/0503595f9ab5bfdef6c06c2d8c2712cb50213259/Hyperconnectivity/Classes/.gitkeep
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/ConnectivityPublisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Publisher.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | public struct ConnectivityPublisher: Publisher {
12 |
13 | // MARK: - Type Definitions
14 | public typealias Configuration = Hyperconnectivity.Configuration
15 | public typealias Failure = Never
16 | public typealias Output = ConnectivityResult
17 |
18 | // MARK: State
19 | private let configuration: Configuration
20 |
21 | public init(configuration: Configuration = Configuration()) {
22 | self.configuration = configuration
23 | }
24 |
25 | public func receive(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
26 | let subscription = ConnectivitySubscription(configuration: configuration, subscriber: subscriber)
27 | subscriber.receive(subscription: subscription)
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/ConnectivitySubscription.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Subscription.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | protocol Connectivity {
12 | var connectivityChanged: Hyperconnectivity.ConnectivityChanged? { get set }
13 | init(configuration: Hyperconnectivity.Configuration)
14 | func startNotifier()
15 | func stopNotifier()
16 | }
17 |
18 | extension Hyperconnectivity: Connectivity {}
19 |
20 | class ConnectivitySubscription: Subscription where S.Input == ConnectivityResult, S.Failure == Never {
21 | private let configuration: Hyperconnectivity.Configuration
22 | private var connectivity: Connectivity?
23 | private var subscriber: S?
24 |
25 | init(configuration: Hyperconnectivity.Configuration, connectivity: Connectivity? = nil, subscriber: S) {
26 | self.configuration = configuration
27 | self.connectivity = connectivity
28 | self.subscriber = subscriber
29 | startNotifier(with: subscriber)
30 | }
31 |
32 | func cancel() {
33 | stopNotifier()
34 | }
35 |
36 | func request(_: Subscribers.Demand) {}
37 | }
38 |
39 | private extension ConnectivitySubscription {
40 |
41 | private func startNotifier(with subscriber: S) {
42 | connectivity = connectivity ?? Hyperconnectivity(configuration: configuration)
43 | let connectivityChanged: (ConnectivityResult) -> Void = { connectivity in
44 | _ = subscriber.receive(connectivity)
45 | }
46 | connectivity?.connectivityChanged = connectivityChanged
47 | connectivity?.startNotifier()
48 | }
49 |
50 | private func stopNotifier() {
51 | connectivity?.stopNotifier()
52 | connectivity = nil
53 | subscriber?.receive(completion: Subscribers.Completion.finished)
54 | subscriber = nil
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/NonCachingURLSessionConfigurationFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NonCachingURLSessionConfigurationFactory.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 20/03/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | struct NonCachingURLSessionConfigurationFactory {
11 | func urlSessionConfiguration(from input: URLSessionConfiguration) -> URLSessionConfiguration {
12 | // Ensure that we never use cached results, including where using a custom `URLSessionConfiguration`.
13 | let output = input.copy() as! URLSessionConfiguration
14 | output.requestCachePolicy = .reloadIgnoringCacheData
15 | output.urlCache = nil
16 | return output
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/Publishers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Publishers.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | extension Publishers {
12 | public typealias Connectivity = ConnectivityPublisher
13 | public typealias Reachability = ReachabilityPublisher
14 | }
15 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/ReachabilityPublisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReachabilityPublisher.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 |
11 | public struct ReachabilityPublisher: Publisher {
12 |
13 | // MARK: - Type Definitions
14 | public typealias Configuration = Hyperconnectivity.Configuration
15 | public typealias Failure = Never
16 | public typealias Output = ReachabilityResult
17 |
18 | // MARK: State
19 | private let configuration: Configuration
20 |
21 | public init(configuration: Configuration = Configuration()) {
22 | self.configuration = configuration.cloneForReachability()
23 | }
24 |
25 | public func receive(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
26 | let subscription = ReachabilitySubscription(configuration: configuration, subscriber: subscriber)
27 | subscriber.receive(subscription: subscription)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Combine/ReachabilitySubscription.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReachabilitySubscription.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class ReachabilitySubscription: Subscription where S.Input == ReachabilityResult, S.Failure == Never {
12 | private let configuration: Hyperconnectivity.Configuration
13 | private var connectivity: Hyperconnectivity?
14 | private var subscriber: S?
15 |
16 | init(configuration: Hyperconnectivity.Configuration, subscriber: S) {
17 | self.configuration = configuration.cloneForReachability()
18 | self.subscriber = subscriber
19 | startNotifier(with: subscriber)
20 | }
21 |
22 | func cancel() {
23 | stopNotifier()
24 | }
25 |
26 | func request(_: Subscribers.Demand) {}
27 | }
28 |
29 | private extension ReachabilitySubscription {
30 |
31 | private func startNotifier(with subscriber: S) {
32 | connectivity = Hyperconnectivity(configuration: configuration)
33 | let reachabilityChanged: (ReachabilityResult) -> Void = { reachability in
34 | _ = subscriber.receive(reachability)
35 | }
36 | connectivity?.reachabilityChanged = reachabilityChanged
37 | connectivity?.startNotifier()
38 | }
39 |
40 | private func stopNotifier() {
41 | connectivity?.stopNotifier()
42 | connectivity = nil
43 | subscriber?.receive(completion: Subscribers.Completion.finished)
44 | subscriber = nil
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Core/Hyperconnectivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Hyperconnectivity.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 | import Network
11 |
12 | public class Hyperconnectivity {
13 |
14 | // MARK: Type declarations
15 | public typealias Configuration = HyperconnectivityConfiguration
16 | public typealias ConnectivityChanged = (ConnectivityResult) -> Void
17 | public typealias Publisher = ConnectivityPublisher
18 | public typealias ReachabilityChanged = (ReachabilityResult) -> Void
19 | public typealias State = ConnectivityState
20 |
21 | // MARK: State
22 | private var cancellable: AnyCancellable?
23 | private let configuration: Configuration
24 | internal var connectivityChanged: ConnectivityChanged?
25 | private let notifier = NotificationCenter.default
26 | private var pathMonitor: NWPathMonitor?
27 | internal var reachabilityChanged: ReachabilityChanged?
28 |
29 | required init(configuration: Configuration = Configuration()) {
30 | self.configuration = configuration
31 | }
32 |
33 | func startNotifier() {
34 | let configuration = self.configuration
35 | let pathMonitor = NWPathMonitor()
36 | pathMonitor.pathUpdateHandler = { [weak self] path in
37 | self?.pathUpdated(path, with: configuration)
38 | }
39 | self.pathMonitor = pathMonitor
40 | notifier.post(name: .ConnectivityDidStart, object: nil)
41 | pathMonitor.start(queue: configuration.connectivityQueue)
42 | }
43 |
44 | func stopNotifier() {
45 | cancellable?.cancel()
46 | cancellable = nil
47 | notifier.post(name: .ConnectivityDidFinish, object: nil)
48 | pathMonitor = nil
49 | }
50 | }
51 |
52 | private extension Hyperconnectivity {
53 | private func checkConnectivity(of path: NWPath, using configuration: Configuration) {
54 | let factory = NonCachingURLSessionConfigurationFactory()
55 | let urlSessionConfiguration = factory.urlSessionConfiguration(from: configuration.urlSessionConfiguration)
56 | let publishers = configuration.connectivityURLRequests.map { urlRequest in
57 | URLSession(configuration: urlSessionConfiguration).dataTaskPublisher(for: urlRequest)
58 | }
59 | let totalChecks = UInt(configuration.connectivityURLRequests.count)
60 | let result = ConnectivityResult(path: path, successThreshold: configuration.successThreshold, totalChecks: totalChecks)
61 | let combinedPublisher = Publishers.MergeMany(publishers)
62 | cancellable = combinedPublisher.sink(receiveCompletion:{ [weak self] _ in
63 | self?.connectivityChanged(result)
64 | }, receiveValue: { [weak self] response in
65 | result.connectivityCheck(successful: configuration.isResponseValid(response))
66 | guard result.isConnected else {
67 | return
68 | }
69 | self?.connectivityChanged(result)
70 | })
71 | }
72 |
73 | private func connectivityChanged(_ result: ConnectivityResult) {
74 | connectivityChanged?(result)
75 | cancellable?.cancel()
76 | notifier.post(name: .ConnectivityDidChange, object: result)
77 | }
78 |
79 | private func handleReachability(for path: NWPath) {
80 | let result = ReachabilityResult(path: path)
81 | reachabilityChanged?(result)
82 | }
83 |
84 | /// Invoked on `NWPath` change by `pathUpdateHandler`.
85 | private func pathUpdated(_ path: NWPath, with configuration: Configuration) {
86 | handleReachability(for: path)
87 | if configuration.shouldCheckConnectivity {
88 | checkConnectivity(of: path, using: configuration)
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/Configuration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Configuration.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct HyperconnectivityConfiguration {
11 | public static let defaultConnectivityURLs = [
12 | URL(string: "https://www.apple.com/library/test/success.html"),
13 | URL(string: "https://captive.apple.com/hotspot-detect.html")
14 | ].compactMap { $0 }
15 |
16 | public static let defaultURLSessionConfiguration: URLSessionConfiguration = {
17 | let sessionConfiguration = URLSessionConfiguration.default
18 | sessionConfiguration.requestCachePolicy = .reloadIgnoringCacheData
19 | sessionConfiguration.urlCache = nil
20 | sessionConfiguration.timeoutIntervalForRequest = 5.0
21 | sessionConfiguration.timeoutIntervalForResource = 5.0
22 | return sessionConfiguration
23 | }()
24 |
25 | let callbackQueue: DispatchQueue
26 | let connectivityQueue: DispatchQueue
27 | let connectivityURLRequests: [URLRequest]
28 | let responseValidator: ResponseValidator
29 | let shouldCheckConnectivity: Bool
30 |
31 | /// % successful connections required to be deemed to have connectivity
32 | let successThreshold: Percentage
33 | let urlSessionConfiguration: URLSessionConfiguration
34 |
35 | public init(
36 | callbackQueue: DispatchQueue = DispatchQueue.main,
37 | connectivityQueue: DispatchQueue = DispatchQueue.global(qos: .utility),
38 | connectivityURLs: [URL] = Self.defaultConnectivityURLs,
39 | responseValidator: ResponseValidator? = nil,
40 | shouldCheckConnectivity: Bool = true,
41 | successThreshold: Percentage = Percentage(50.0),
42 | urlSessionConfiguration: URLSessionConfiguration = Self.defaultURLSessionConfiguration
43 | ) {
44 | self.init(
45 | callbackQueue: callbackQueue,
46 | connectivityQueue: connectivityQueue,
47 | connectivityURLRequests: connectivityURLs.map { URLRequest(url: $0) },
48 | responseValidator: responseValidator,
49 | shouldCheckConnectivity: shouldCheckConnectivity,
50 | successThreshold: successThreshold,
51 | urlSessionConfiguration: urlSessionConfiguration
52 | )
53 | }
54 |
55 | public init(
56 | callbackQueue: DispatchQueue = DispatchQueue.main,
57 | connectivityQueue: DispatchQueue = DispatchQueue.global(qos: .utility),
58 | connectivityURLRequests: [URLRequest],
59 | responseValidator: ResponseValidator? = nil,
60 | shouldCheckConnectivity: Bool = true,
61 | successThreshold: Percentage = Percentage(50.0),
62 | urlSessionConfiguration: URLSessionConfiguration = Self.defaultURLSessionConfiguration
63 | ) {
64 | let defaultValidator = ResponseStringValidator(
65 | validationMode: .containsExpectedResponseString
66 | )
67 | self.callbackQueue = callbackQueue
68 | self.connectivityQueue = connectivityQueue
69 | self.connectivityURLRequests = connectivityURLRequests
70 | self.responseValidator = responseValidator ?? defaultValidator
71 | self.shouldCheckConnectivity = shouldCheckConnectivity
72 | self.successThreshold = successThreshold
73 | self.urlSessionConfiguration = urlSessionConfiguration
74 | }
75 |
76 | func cloneForReachability() -> Self {
77 | return HyperconnectivityConfiguration(
78 | callbackQueue: callbackQueue,
79 | connectivityQueue: connectivityQueue,
80 | connectivityURLs: [],
81 | responseValidator: responseValidator,
82 | shouldCheckConnectivity: false,
83 | successThreshold: Percentage(0.0),
84 | urlSessionConfiguration: urlSessionConfiguration)
85 | }
86 |
87 | /// Convenience method for determining whether or not the response is valid.
88 | func isResponseValid(_ response: (Data, URLResponse)) -> Bool {
89 | responseValidator.isResponseValid(response.1, data: response.0)
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/Connection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Connection.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Network
10 |
11 | protocol Path {
12 | var isExpensive: Bool { get }
13 | func usesInterfaceType(_ type: NWInterface.InterfaceType) -> Bool
14 | }
15 |
16 | extension NWPath: Path {}
17 |
18 | public enum Connection {
19 | case cellular
20 | case disconnected
21 | case ethernet
22 | case loopback
23 | case other
24 | case wifi
25 |
26 | init(_ path: Path) {
27 | if path.usesInterfaceType(.wiredEthernet) {
28 | self = .ethernet
29 | } else if path.usesInterfaceType(.wifi) {
30 | self = .wifi
31 | } else if path.usesInterfaceType(.cellular) {
32 | self = .cellular
33 | } else if path.usesInterfaceType(.other) {
34 | self = .other
35 | } else if path.usesInterfaceType(.loopback) {
36 | self = .loopback
37 | } else {
38 | self = .disconnected
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/ConnectivityResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Result.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Network
10 |
11 | public class ConnectivityResult {
12 | public let connection: Connection
13 | public var isConnected: Bool {
14 | isThresholdMet(successPercentage, threshold: successThreshold)
15 | }
16 | public let isExpensive: Bool
17 | public var state: Hyperconnectivity.State {
18 | Hyperconnectivity.State(connection: connection, isConnected: isConnected)
19 | }
20 | private var successfulChecks: UInt = 0
21 | private let successThreshold: Percentage
22 | private let totalChecks: UInt
23 | private var successPercentage: Percentage {
24 | Percentage(successfulChecks, outOf: totalChecks)
25 | }
26 |
27 | init(path: Path, successThreshold: Percentage, totalChecks: UInt) {
28 | connection = Connection(path)
29 | isExpensive = path.isExpensive
30 | self.successThreshold = successThreshold
31 | self.totalChecks = totalChecks
32 | }
33 |
34 | func connectivityCheck(successful: Bool) {
35 | if successful {
36 | successfulChecks += 1
37 | }
38 | }
39 |
40 | private func isThresholdMet(_ percentage: Percentage, threshold: Percentage) -> Bool {
41 | return percentage >= threshold
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/ConnectivityState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // State.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public enum ConnectivityState {
11 | case cellularWithInternet
12 | case cellularWithoutInternet
13 | case disconnected
14 | case ethernetWithInternet
15 | case ethernetWithoutInternet
16 | case loopback
17 | case otherWithInternet
18 | case otherWithoutInternet
19 | case wifiWithInternet
20 | case wifiWithoutInternet
21 |
22 | init(connection: Connection, isConnected: Bool) {
23 | switch connection {
24 | case .cellular:
25 | self = (isConnected) ? .cellularWithInternet : .cellularWithoutInternet
26 | case .disconnected:
27 | self = .disconnected
28 | case .ethernet:
29 | self = (isConnected) ? .ethernetWithInternet : .ethernetWithoutInternet
30 | case .loopback:
31 | self = .loopback
32 | case .other:
33 | self = (isConnected) ? .otherWithInternet : .otherWithoutInternet
34 | case .wifi:
35 | self = (isConnected) ? .wifiWithInternet : .wifiWithoutInternet
36 | }
37 | }
38 | }
39 |
40 | extension ConnectivityState: CustomStringConvertible {
41 | public var description: String {
42 | switch self {
43 | case .cellularWithInternet:
44 | return "Cellular with Internet connectivity"
45 | case .cellularWithoutInternet:
46 | return "Cellular without Internet connectivity"
47 | case .disconnected:
48 | return "Disconnected"
49 | case .ethernetWithInternet:
50 | return "Ethernet with Internet connectivity"
51 | case .ethernetWithoutInternet:
52 | return "Ethernet without Internet connectivity"
53 | case .loopback:
54 | return "Loopback"
55 | case .otherWithInternet:
56 | return "Other with Internet connectivity"
57 | case .otherWithoutInternet:
58 | return "Other without Internet connectivity"
59 | case .wifiWithInternet:
60 | return "Wi-Fi with Internet connectivity"
61 | case .wifiWithoutInternet:
62 | return "Wi-Fi without Internet connectivity"
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/Notification.Name.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notification.Name.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 16/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Notification.Name {
11 |
12 | // Connectivity
13 | public static let ConnectivityDidStart = Notification.Name("kNetworkConnectivityStartedNotification")
14 | public static let ConnectivityDidChange = Notification.Name("kNetworkConnectivityChangedNotification")
15 | public static let ConnectivityDidFinish = Notification.Name("kNetworkConnectivityFinishedNotification")
16 |
17 | // Reachability
18 | public static let ReachabilityDidChange = Notification.Name("kNetworkReachabilityChangedNotification")
19 | }
20 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/Percentage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Percentage.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 07/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct Percentage: Comparable {
11 | let value: Double
12 |
13 | public init(_ value: Double) {
14 | var result = value < 0.0 ? 0.0 : value
15 | result = result > 100.0 ? 100.0 : result
16 | self.value = result
17 | }
18 |
19 | public init(_ value: UInt, outOf total: UInt) {
20 | self.init(Double(value), outOf: Double(total))
21 | }
22 |
23 | public init(_ value: Double, outOf total: Double) {
24 | guard total > 0 else {
25 | self.init(0.0)
26 | return
27 | }
28 | self.init((value / total) * 100.0)
29 | }
30 |
31 | public static func < (lhs: Self, rhs: Self) -> Bool {
32 | return lhs.value < rhs.value
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Model/ReachabilityResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReachabilityResult.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 | import Network
10 |
11 | public struct ReachabilityResult {
12 |
13 | public let connection: Connection
14 | public let isExpensive: Bool
15 | public let isReachable: Bool
16 |
17 | init(path: NWPath) {
18 | connection = Connection(path)
19 | isExpensive = path.isExpensive
20 | isReachable = path.status == .satisfied
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Response Validation/ResponseContainsStringValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseContainsValidator.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public class ResponseContainsStringValidator: ResponseValidator {
11 |
12 | /// The `String` expected to be contained in the response
13 | public let expectedResponse: String
14 |
15 | /// Initializes the receiver to validate that the response `String` contains the expected response.
16 | ///
17 | /// - Parameter expectedResponse: The `String` expected to be contained in the response.
18 | public init(expectedResponse: String = "Success") {
19 | self.expectedResponse = expectedResponse
20 | }
21 |
22 | public func isResponseValid(_ response: URLResponse, data: Data) -> Bool {
23 | guard let responseString = String(data: data, encoding: .utf8) else {
24 | return false
25 | }
26 | return responseString.contains(expectedResponse)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Response Validation/ResponseRegExValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseRegExValidator.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public class ResponseRegExValidator: ResponseValidator {
11 |
12 | public static let defaultRegularExpression = ".*?.*?Success.*?.*"
13 |
14 | /// Matching options for determining how the response is matched against the regular expression.
15 | private let options: NSRegularExpression.Options
16 |
17 | /// Response `String` is matched against the regex to determine whether or not the response is valid.
18 | private let regularExpression: String
19 |
20 | /// Initializes the receiver to validate the response against a supplied regular expression.
21 | /// - Parameters:
22 | /// - options: Matching options for determining whether or not the response `String`
23 | /// matching the provided regular expression.
24 | /// - regEx: Regular expression used to validate the response. If the response
25 | /// `String` matches the regular expression then the response is deemed to be valid.
26 | public init(regEx: String = ResponseRegExValidator.defaultRegularExpression,
27 | options: NSRegularExpression.Options? = nil
28 | ) {
29 | self.options = options ?? [.caseInsensitive, .allowCommentsAndWhitespace, .dotMatchesLineSeparators]
30 | self.regularExpression = regEx
31 | }
32 |
33 | public func isResponseValid(_ response: URLResponse, data: Data) -> Bool {
34 | guard let responseString = String(data: data, encoding: .utf8),
35 | let regEx = try? NSRegularExpression(pattern: regularExpression, options: options) else {
36 | return false
37 | }
38 | let responseStrRange = NSRange(location: 0, length: responseString.count)
39 | let matches = regEx.matches(in: responseString, options: [], range: responseStrRange)
40 | return !matches.isEmpty
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Response Validation/ResponseStringEqualityValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseStringEqualityValidator.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public class ResponseStringEqualityValidator: ResponseValidator {
11 |
12 | /// The `String` expected as the response
13 | public let expectedResponse: String
14 |
15 | /// Initializes the receiver to validate that the response `String` is equal to the expected response.
16 | ///
17 | /// - Parameter expectedResponse: The `String` expected as the response.
18 | public init(expectedResponse: String = "Success") {
19 | self.expectedResponse = expectedResponse
20 | }
21 |
22 | public func isResponseValid(_ response: URLResponse, data: Data) -> Bool {
23 | guard let responseString = String(data: data, encoding: .utf8) else {
24 | return false
25 | }
26 | return expectedResponse == responseString.trimmingCharacters(in: .whitespacesAndNewlines)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Response Validation/ResponseStringValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseStringValidation.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public class ResponseStringValidator: ResponseValidator {
11 |
12 | public enum ValidationMode: Int {
13 | case containsExpectedResponseString
14 | case equalsExpectedResponseString
15 | case matchesRegularExpression
16 | }
17 |
18 | /// The method used to validate the response from the connectivity endpoints.
19 | public let responseValidationMode: ValidationMode
20 |
21 | /// The `String` expected in the response, which is tested based on the validationMode
22 | public let expectedResponse: String?
23 |
24 | /// Initializes the receiver to validate response `String`s
25 | /// using the given validation mode
26 | ///
27 | /// - Parameter validationMode: The mode to use for validating the response `String`.
28 | /// - Parameter expectedResponse: The `String` expected in the response, which is
29 | /// tested based on the validationMode
30 | public init(validationMode: ValidationMode, expectedResponse: String? = nil) {
31 | self.responseValidationMode = validationMode
32 | self.expectedResponse = expectedResponse
33 | }
34 |
35 | public func isResponseValid(_ response: URLResponse, data: Data) -> Bool {
36 | let validator: ResponseValidator
37 | guard let expectedResponse = self.expectedResponse else {
38 | switch responseValidationMode {
39 | case .containsExpectedResponseString:
40 | validator = ResponseContainsStringValidator()
41 | case .equalsExpectedResponseString:
42 | validator = ResponseStringEqualityValidator()
43 | case .matchesRegularExpression:
44 | validator = ResponseRegExValidator()
45 | }
46 | return validator.isResponseValid(response, data: data)
47 | }
48 | switch responseValidationMode {
49 | case .containsExpectedResponseString:
50 | validator = ResponseContainsStringValidator(expectedResponse: expectedResponse)
51 | case .equalsExpectedResponseString:
52 | validator = ResponseStringEqualityValidator(expectedResponse: expectedResponse)
53 | case .matchesRegularExpression:
54 | validator = ResponseRegExValidator(regEx: expectedResponse)
55 | }
56 | return validator.isResponseValid(response, data: data)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Hyperconnectivity/Classes/Response Validation/ResponseValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseValidation.swift
3 | // Hyperconnectivity
4 | //
5 | // Created by Ross Butler on 08/05/2020.
6 | //
7 |
8 | import Foundation
9 |
10 | /// The contract for a response validator used to determine
11 | /// connectivity based on a network response
12 | public protocol ResponseValidator {
13 |
14 | /// Determines whether or not the response is valid
15 | /// and expected for a given `URL`
16 | ///
17 | /// - Parameter url: The `URL`, from which the response was fetched
18 | /// - Parameter _ response: The `URLResponse` returned by url
19 | /// - Parameter data: The data in the response returned by url
20 | func isResponseValid(_ response: URLResponse, data: Data) -> Bool
21 | }
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020 Ross Butler
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "ohhttpstubs",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/AliSoftware/OHHTTPStubs",
7 | "state" : {
8 | "revision" : "12f19662426d0434d6c330c6974d53e2eb10ecd9",
9 | "version" : "9.1.0"
10 | }
11 | }
12 | ],
13 | "version" : 2
14 | }
15 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.7
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "Hyperconnectivity",
6 | platforms: [
7 | .iOS(.v13),
8 | .tvOS(.v13),
9 | .macOS(.v10_15),
10 | .watchOS(.v6)
11 | ],
12 | products: [
13 | .library(
14 | name: "Hyperconnectivity",
15 | targets: ["Hyperconnectivity"]
16 | )
17 | ],
18 | dependencies: [
19 | .package(url: "https://github.com/AliSoftware/OHHTTPStubs", from: "9.1.0")
20 | ],
21 | targets: [
22 | .target(
23 | name: "Hyperconnectivity",
24 | path: "Hyperconnectivity/Classes"
25 | ),
26 | .testTarget(
27 | name: "HyperconnectivityTests",
28 | dependencies: [
29 | .target(name: "Hyperconnectivity"),
30 | .product(name: "OHHTTPStubsSwift", package: "OHHTTPStubs")
31 | ],
32 | path: "Example/Tests",
33 | resources: [
34 | .process("failure-response.html"),
35 | .process("string-contains-response.html"),
36 | .process("string-equality-response.html")
37 | ]
38 | )
39 | ]
40 | )
41 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------
/docs/images/comparison-with-connectivity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwbutler/Hyperconnectivity/0503595f9ab5bfdef6c06c2d8c2712cb50213259/docs/images/comparison-with-connectivity.png
--------------------------------------------------------------------------------
/docs/images/hyperconnectivity-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwbutler/Hyperconnectivity/0503595f9ab5bfdef6c06c2d8c2712cb50213259/docs/images/hyperconnectivity-banner.png
--------------------------------------------------------------------------------
/docs/images/hyperconnectivity-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwbutler/Hyperconnectivity/0503595f9ab5bfdef6c06c2d8c2712cb50213259/docs/images/hyperconnectivity-logo.png
--------------------------------------------------------------------------------