FIRReachabilityCheckerTest.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // Copyright 2018 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FIRTestCase.h"
  15. #import <FirebaseCore/FIRReachabilityChecker+Internal.h>
  16. #import <FirebaseCore/FIRReachabilityChecker.h>
  17. @interface FIRReachabilityCheckerTest : FIRTestCase <FIRReachabilityDelegate> {
  18. @private
  19. FIRReachabilityChecker *checker_;
  20. NSMutableArray *statuses_;
  21. BOOL createFail_;
  22. BOOL setCallbackFail_;
  23. BOOL scheduleUnscheduleFail_;
  24. }
  25. - (void *)createReachabilityWithAllocator:(CFAllocatorRef)allocator withName:(const char *)hostname;
  26. - (BOOL)reachability:(const void *)reachability
  27. setCallback:(SCNetworkReachabilityCallBack)callback
  28. withContext:(SCNetworkReachabilityContext *)context;
  29. - (BOOL)scheduleReachability:(const void *)reachability
  30. runLoop:(CFRunLoopRef)runLoop
  31. runLoopMode:(CFStringRef)runLoopMode;
  32. - (BOOL)unscheduleReachability:(const void *)reachability
  33. runLoop:(CFRunLoopRef)runLoop
  34. runLoopMode:(CFStringRef)runLoopMode;
  35. - (void)releaseReachability:(const void *)reachability;
  36. @end
  37. static NSString *const kHostname = @"www.google.com";
  38. static const void *kFakeReachabilityObject = (const void *)0x8badf00d;
  39. static FIRReachabilityCheckerTest *FakeReachabilityTest = nil;
  40. static struct {
  41. int callsMade;
  42. int createCall;
  43. int setCallbackCall;
  44. int scheduleCall;
  45. int unscheduleCall;
  46. int releaseCall;
  47. void (*callback)(SCNetworkReachabilityRef, SCNetworkReachabilityFlags, void *info);
  48. void *callbackInfo;
  49. } FakeReachability;
  50. static SCNetworkReachabilityRef ReachabilityCreateWithName(CFAllocatorRef allocator,
  51. const char *hostname) {
  52. return (SCNetworkReachabilityRef)
  53. [FakeReachabilityTest createReachabilityWithAllocator:allocator withName:hostname];
  54. }
  55. static Boolean ReachabilitySetCallback(SCNetworkReachabilityRef reachability,
  56. SCNetworkReachabilityCallBack callback,
  57. SCNetworkReachabilityContext *context) {
  58. return [FakeReachabilityTest reachability:reachability setCallback:callback withContext:context];
  59. }
  60. static Boolean ReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef reachability,
  61. CFRunLoopRef runLoop,
  62. CFStringRef runLoopMode) {
  63. return [FakeReachabilityTest scheduleReachability:reachability
  64. runLoop:runLoop
  65. runLoopMode:runLoopMode];
  66. }
  67. static Boolean ReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef reachability,
  68. CFRunLoopRef runLoop,
  69. CFStringRef runLoopMode) {
  70. return [FakeReachabilityTest unscheduleReachability:reachability
  71. runLoop:runLoop
  72. runLoopMode:runLoopMode];
  73. }
  74. static void ReachabilityRelease(CFTypeRef reachability) {
  75. [FakeReachabilityTest releaseReachability:reachability];
  76. }
  77. static const struct FIRReachabilityApi kTestReachabilityApi = {
  78. ReachabilityCreateWithName, ReachabilitySetCallback, ReachabilityScheduleWithRunLoop,
  79. ReachabilityUnscheduleFromRunLoop, ReachabilityRelease,
  80. };
  81. @implementation FIRReachabilityCheckerTest
  82. - (void)resetFakeReachability {
  83. FakeReachabilityTest = self;
  84. FakeReachability.callsMade = 0;
  85. FakeReachability.createCall = -1;
  86. FakeReachability.setCallbackCall = -1;
  87. FakeReachability.scheduleCall = -1;
  88. FakeReachability.unscheduleCall = -1;
  89. FakeReachability.releaseCall = -1;
  90. FakeReachability.callback = NULL;
  91. FakeReachability.callbackInfo = NULL;
  92. }
  93. - (void)setUp {
  94. [super setUp];
  95. [self resetFakeReachability];
  96. createFail_ = NO;
  97. setCallbackFail_ = NO;
  98. scheduleUnscheduleFail_ = NO;
  99. checker_ = [[FIRReachabilityChecker alloc] initWithReachabilityDelegate:self
  100. loggerDelegate:nil
  101. withHost:kHostname];
  102. statuses_ = [[NSMutableArray alloc] init];
  103. }
  104. - (void *)createReachabilityWithAllocator:(CFAllocatorRef)allocator
  105. withName:(const char *)hostname {
  106. XCTAssertTrue(allocator == kCFAllocatorDefault, @"");
  107. XCTAssertEqual(strcmp(hostname, [kHostname UTF8String]), 0, @"");
  108. XCTAssertEqual(FakeReachability.callsMade, 0, @"create call must always come first.");
  109. XCTAssertEqual(FakeReachability.createCall, -1, @"create call must only be called once.");
  110. FakeReachability.createCall = ++FakeReachability.callsMade;
  111. return createFail_ ? NULL : (void *)kFakeReachabilityObject;
  112. }
  113. - (BOOL)reachability:(const void *)reachability
  114. setCallback:(SCNetworkReachabilityCallBack)callback
  115. withContext:(SCNetworkReachabilityContext *)context {
  116. XCTAssertEqual(reachability, kFakeReachabilityObject, @"got bad object");
  117. XCTAssertEqual((int)context->version, 0, @"");
  118. XCTAssertEqual(context->info, (__bridge void *)checker_, @"");
  119. XCTAssertEqual((void *)context->retain, NULL, @"");
  120. XCTAssertEqual((void *)context->release, NULL, @"");
  121. XCTAssertEqual((void *)context->copyDescription, NULL, @"");
  122. XCTAssertEqual(FakeReachability.setCallbackCall, -1, @"setCallback should only be called once.");
  123. FakeReachability.setCallbackCall = ++FakeReachability.callsMade;
  124. XCTAssertTrue(callback != NULL, @"");
  125. FakeReachability.callback = callback;
  126. XCTAssertTrue(context->info != NULL, @"");
  127. FakeReachability.callbackInfo = context->info;
  128. return setCallbackFail_ ? NO : YES;
  129. }
  130. - (BOOL)scheduleReachability:(const void *)reachability
  131. runLoop:(CFRunLoopRef)runLoop
  132. runLoopMode:(CFStringRef)runLoopMode {
  133. XCTAssertEqual(reachability, kFakeReachabilityObject, @"got bad object");
  134. XCTAssertEqual(runLoop, CFRunLoopGetMain(), @"bad run loop");
  135. XCTAssertEqualObjects((__bridge NSString *)runLoopMode,
  136. (__bridge NSString *)kCFRunLoopCommonModes, @"bad run loop mode");
  137. XCTAssertEqual(FakeReachability.scheduleCall, -1,
  138. @"scheduleWithRunLoop should only be called once.");
  139. FakeReachability.scheduleCall = ++FakeReachability.callsMade;
  140. return scheduleUnscheduleFail_ ? NO : YES;
  141. }
  142. - (BOOL)unscheduleReachability:(const void *)reachability
  143. runLoop:(CFRunLoopRef)runLoop
  144. runLoopMode:(CFStringRef)runLoopMode {
  145. XCTAssertEqual(reachability, kFakeReachabilityObject, @"got bad object");
  146. XCTAssertEqual(runLoop, CFRunLoopGetMain(), @"bad run loop");
  147. XCTAssertEqualObjects((__bridge NSString *)runLoopMode,
  148. (__bridge NSString *)kCFRunLoopCommonModes, @"bad run loop mode");
  149. XCTAssertEqual(FakeReachability.unscheduleCall, -1,
  150. @"unscheduleFromRunLoop should only be called once.");
  151. FakeReachability.unscheduleCall = ++FakeReachability.callsMade;
  152. return scheduleUnscheduleFail_ ? NO : YES;
  153. }
  154. - (void)releaseReachability:(const void *)reachability {
  155. XCTAssertEqual(reachability, kFakeReachabilityObject, @"got bad object");
  156. XCTAssertEqual(FakeReachability.releaseCall, -1, @"release should only be called once.");
  157. FakeReachability.releaseCall = ++FakeReachability.callsMade;
  158. }
  159. - (void)reachability:(FIRReachabilityChecker *)reachability
  160. statusChanged:(FIRReachabilityStatus)status {
  161. [statuses_ addObject:[NSNumber numberWithInt:(int)status]];
  162. }
  163. #pragma mark - Test
  164. - (void)testApiHappyPath {
  165. [checker_ setReachabilityApi:&kTestReachabilityApi];
  166. XCTAssertEqual([checker_ reachabilityApi], &kTestReachabilityApi, @"");
  167. XCTAssertFalse(checker_.isActive, @"");
  168. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  169. XCTAssertTrue([checker_ start], @"");
  170. XCTAssertTrue(checker_.isActive, @"");
  171. XCTAssertEqual([statuses_ count], (NSUInteger)0, @"");
  172. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  173. FakeReachability.callback(kFakeReachabilityObject, 0, FakeReachability.callbackInfo);
  174. XCTAssertEqual([statuses_ count], (NSUInteger)1, @"");
  175. XCTAssertEqual([(NSNumber *)[statuses_ objectAtIndex:0] intValue],
  176. (int)kFIRReachabilityNotReachable, @"");
  177. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityNotReachable, @"");
  178. FakeReachability.callback(kFakeReachabilityObject, kSCNetworkReachabilityFlagsReachable,
  179. FakeReachability.callbackInfo);
  180. XCTAssertEqual([statuses_ count], (NSUInteger)2, @"");
  181. XCTAssertEqual([(NSNumber *)[statuses_ objectAtIndex:1] intValue], (int)kFIRReachabilityViaWifi,
  182. @"");
  183. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityViaWifi, @"");
  184. FakeReachability.callback(
  185. kFakeReachabilityObject,
  186. kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsConnectionRequired,
  187. FakeReachability.callbackInfo);
  188. XCTAssertEqual([statuses_ count], (NSUInteger)3, @"");
  189. XCTAssertEqual([(NSNumber *)[statuses_ objectAtIndex:2] intValue],
  190. (int)kFIRReachabilityNotReachable, @"");
  191. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityNotReachable, @"");
  192. #if TARGET_OS_IOS || TARGET_OS_TV
  193. FakeReachability.callback(
  194. kFakeReachabilityObject,
  195. kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsIsWWAN,
  196. FakeReachability.callbackInfo);
  197. XCTAssertEqual([statuses_ count], (NSUInteger)4, @"");
  198. XCTAssertEqual([(NSNumber *)[statuses_ objectAtIndex:3] intValue],
  199. (int)kFIRReachabilityViaCellular, @"");
  200. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityViaCellular, @"");
  201. FakeReachability.callback(kFakeReachabilityObject, kSCNetworkReachabilityFlagsIsWWAN,
  202. FakeReachability.callbackInfo);
  203. XCTAssertEqual([statuses_ count], (NSUInteger)5, @"");
  204. XCTAssertEqual([(NSNumber *)[statuses_ objectAtIndex:4] intValue],
  205. (int)kFIRReachabilityNotReachable, @"");
  206. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityNotReachable, @"");
  207. #endif
  208. [checker_ stop];
  209. XCTAssertFalse(checker_.isActive, @"");
  210. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  211. XCTAssertEqual(FakeReachability.callsMade, 5, @"");
  212. XCTAssertEqual(FakeReachability.createCall, 1, @"");
  213. XCTAssertEqual(FakeReachability.setCallbackCall, 2, @"");
  214. XCTAssertEqual(FakeReachability.scheduleCall, 3, @"");
  215. XCTAssertEqual(FakeReachability.unscheduleCall, 4, @"");
  216. XCTAssertEqual(FakeReachability.releaseCall, 5, @"");
  217. }
  218. - (void)testApiCreateFail {
  219. [checker_ setReachabilityApi:&kTestReachabilityApi];
  220. XCTAssertEqual([checker_ reachabilityApi], &kTestReachabilityApi, @"");
  221. createFail_ = YES;
  222. XCTAssertFalse(checker_.isActive, @"");
  223. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  224. XCTAssertFalse([checker_ start], @"");
  225. XCTAssertFalse(checker_.isActive, @"");
  226. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  227. [checker_ stop];
  228. XCTAssertFalse(checker_.isActive, @"");
  229. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  230. XCTAssertEqual(FakeReachability.callsMade, 1, @"");
  231. XCTAssertEqual(FakeReachability.createCall, 1, @"");
  232. XCTAssertEqual(FakeReachability.setCallbackCall, -1, @"");
  233. XCTAssertEqual(FakeReachability.scheduleCall, -1, @"");
  234. XCTAssertEqual(FakeReachability.unscheduleCall, -1, @"");
  235. XCTAssertEqual(FakeReachability.releaseCall, -1, @"");
  236. XCTAssertEqual([statuses_ count], (NSUInteger)0, @"");
  237. }
  238. - (void)testApiCallbackFail {
  239. [checker_ setReachabilityApi:&kTestReachabilityApi];
  240. XCTAssertEqual([checker_ reachabilityApi], &kTestReachabilityApi, @"");
  241. setCallbackFail_ = YES;
  242. XCTAssertFalse(checker_.isActive, @"");
  243. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  244. XCTAssertFalse([checker_ start], @"");
  245. XCTAssertFalse(checker_.isActive, @"");
  246. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  247. [checker_ stop];
  248. XCTAssertFalse(checker_.isActive, @"");
  249. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  250. XCTAssertEqual(FakeReachability.callsMade, 3, @"");
  251. XCTAssertEqual(FakeReachability.createCall, 1, @"");
  252. XCTAssertEqual(FakeReachability.setCallbackCall, 2, @"");
  253. XCTAssertEqual(FakeReachability.scheduleCall, -1, @"");
  254. XCTAssertEqual(FakeReachability.unscheduleCall, -1, @"");
  255. XCTAssertEqual(FakeReachability.releaseCall, 3, @"");
  256. XCTAssertEqual([statuses_ count], (NSUInteger)0, @"");
  257. }
  258. - (void)testApiScheduleFail {
  259. [checker_ setReachabilityApi:&kTestReachabilityApi];
  260. XCTAssertEqual([checker_ reachabilityApi], &kTestReachabilityApi, @"");
  261. scheduleUnscheduleFail_ = YES;
  262. XCTAssertFalse(checker_.isActive, @"");
  263. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  264. XCTAssertFalse([checker_ start], @"");
  265. XCTAssertFalse(checker_.isActive, @"");
  266. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  267. [checker_ stop];
  268. XCTAssertFalse(checker_.isActive, @"");
  269. XCTAssertEqual(checker_.reachabilityStatus, kFIRReachabilityUnknown, @"");
  270. XCTAssertEqual(FakeReachability.callsMade, 4, @"");
  271. XCTAssertEqual(FakeReachability.createCall, 1, @"");
  272. XCTAssertEqual(FakeReachability.setCallbackCall, 2, @"");
  273. XCTAssertEqual(FakeReachability.scheduleCall, 3, @"");
  274. XCTAssertEqual(FakeReachability.unscheduleCall, -1, @"");
  275. XCTAssertEqual(FakeReachability.releaseCall, 4, @"");
  276. XCTAssertEqual([statuses_ count], (NSUInteger)0, @"");
  277. }
  278. - (void)testBadHost {
  279. XCTAssertNil([[FIRReachabilityChecker alloc]
  280. initWithReachabilityDelegate:self
  281. loggerDelegate:(id<FIRNetworkLoggerDelegate>)self
  282. withHost:nil],
  283. @"Creating a checker with nil hostname must fail.");
  284. XCTAssertNil([[FIRReachabilityChecker alloc]
  285. initWithReachabilityDelegate:self
  286. loggerDelegate:(id<FIRNetworkLoggerDelegate>)self
  287. withHost:@""],
  288. @"Creating a checker with empty hostname must fail.");
  289. }
  290. @end