FIRAuthAPNSTokenManagerTests.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <TargetConditionals.h>
  17. #if TARGET_OS_IOS
  18. #import <OCMock/OCMock.h>
  19. #import <XCTest/XCTest.h>
  20. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h"
  21. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h"
  22. NS_ASSUME_NONNULL_BEGIN
  23. /** @var kRegistrationTimeout
  24. @brief The registration timeout used for testing.
  25. */
  26. static const NSTimeInterval kRegistrationTimeout = .5;
  27. /** @var kExpectationTimeout
  28. @brief The test expectation timeout.
  29. @remarks This must be considerably greater than @c kVerificationTimeout .
  30. */
  31. static const NSTimeInterval kExpectationTimeout = 2;
  32. /** @class FIRAuthLegacyUIApplication
  33. @brief A fake legacy (< iOS 7) UIApplication class.
  34. @remarks A custom class is needed because `respondsToSelector:` itself cannot be mocked.
  35. */
  36. @interface FIRAuthLegacyUIApplication : NSObject
  37. #pragma clang diagnostic push
  38. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  39. - (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types;
  40. #pragma clang diagnostic pop
  41. @end
  42. @implementation FIRAuthLegacyUIApplication
  43. #pragma clang diagnostic push
  44. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  45. - (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types {
  46. }
  47. #pragma clang diagnostic pop
  48. @end
  49. /** @class FIRAuthAPNSTokenManagerTests
  50. @brief Unit tests for @c FIRAuthAPNSTokenManager .
  51. */
  52. @interface FIRAuthAPNSTokenManagerTests : XCTestCase
  53. @end
  54. @implementation FIRAuthAPNSTokenManagerTests {
  55. /** @var _mockApplication
  56. @brief The mock application for testing.
  57. */
  58. id _mockApplication;
  59. /** @var _manager
  60. @brief The @c FIRAuthAPNSTokenManager instance under tests.
  61. */
  62. FIRAuthAPNSTokenManager *_manager;
  63. /** @var _data
  64. @brief One piece of data used for testing.
  65. */
  66. NSData *_data;
  67. /** @var _otherData
  68. @brief Another piece of data used for testing.
  69. */
  70. NSData *_otherData;
  71. /** @var _error
  72. @brief The fake error used for testing.
  73. */
  74. NSError *_error;
  75. }
  76. - (void)setUp {
  77. _mockApplication = OCMClassMock([UIApplication class]);
  78. _manager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:_mockApplication];
  79. _data = [@"qwerty" dataUsingEncoding:NSUTF8StringEncoding];
  80. _otherData = [@"!@#$" dataUsingEncoding:NSUTF8StringEncoding];
  81. }
  82. /** @fn testSetToken
  83. @brief Tests setting and getting the `token` property.
  84. */
  85. - (void)testSetToken {
  86. XCTAssertNil(_manager.token);
  87. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeProd];
  88. XCTAssertEqualObjects(_manager.token.data, _data);
  89. XCTAssertEqual(_manager.token.type, FIRAuthAPNSTokenTypeProd);
  90. _manager.token = nil;
  91. XCTAssertNil(_manager.token);
  92. }
  93. /** @fn testDetectTokenType
  94. @brief Tests automatic detection of token type.
  95. */
  96. - (void)testDetectTokenType {
  97. XCTAssertNil(_manager.token);
  98. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeUnknown];
  99. XCTAssertEqualObjects(_manager.token.data, _data);
  100. XCTAssertNotEqual(_manager.token.type, FIRAuthAPNSTokenTypeUnknown);
  101. }
  102. /** @fn testCallback
  103. @brief Tests callbacks are called.
  104. */
  105. - (void)testCallback {
  106. // Add first callback, which is yet to be called.
  107. OCMExpect([_mockApplication registerForRemoteNotifications]);
  108. __block BOOL firstCallbackCalled = NO;
  109. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  110. XCTAssertEqualObjects(token.data, self->_data);
  111. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  112. XCTAssertNil(error);
  113. firstCallbackCalled = YES;
  114. }];
  115. XCTAssertFalse(firstCallbackCalled);
  116. // Add second callback, which is yet to be called either.
  117. __block BOOL secondCallbackCalled = NO;
  118. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  119. XCTAssertEqualObjects(token.data, self->_data);
  120. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  121. XCTAssertNil(error);
  122. secondCallbackCalled = YES;
  123. }];
  124. XCTAssertFalse(secondCallbackCalled);
  125. // Setting nil token shouldn't trigger either callbacks.
  126. _manager.token = nil;
  127. XCTAssertFalse(firstCallbackCalled);
  128. XCTAssertFalse(secondCallbackCalled);
  129. XCTAssertNil(_manager.token);
  130. // Setting a real token should trigger both callbacks.
  131. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeSandbox];
  132. XCTAssertTrue(firstCallbackCalled);
  133. XCTAssertTrue(secondCallbackCalled);
  134. XCTAssertEqualObjects(_manager.token.data, _data);
  135. XCTAssertEqual(_manager.token.type, FIRAuthAPNSTokenTypeSandbox);
  136. // Add third callback, which should be called back immediately.
  137. __block BOOL thirdCallbackCalled = NO;
  138. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  139. XCTAssertEqualObjects(token.data, self->_data);
  140. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  141. XCTAssertNil(error);
  142. thirdCallbackCalled = YES;
  143. }];
  144. XCTAssertTrue(thirdCallbackCalled);
  145. // Verify the mock in the main thread.
  146. XCTestExpectation *expectation = [self expectationWithDescription:@"verify mock"];
  147. dispatch_async(dispatch_get_main_queue(), ^{
  148. OCMVerifyAll(self->_mockApplication);
  149. [expectation fulfill];
  150. });
  151. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  152. }
  153. /** @fn testTimeout
  154. @brief Tests callbacks can be timed out.
  155. */
  156. - (void)testTimeout {
  157. // Set up timeout.
  158. XCTAssertGreaterThan(_manager.timeout, 0);
  159. _manager.timeout = kRegistrationTimeout;
  160. // Add callback to time out.
  161. OCMExpect([_mockApplication registerForRemoteNotifications]);
  162. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  163. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  164. XCTAssertNil(token);
  165. XCTAssertNil(error);
  166. [expectation fulfill];
  167. }];
  168. // Time out.
  169. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  170. OCMVerifyAll(_mockApplication);
  171. // Calling cancel afterwards should have no effect.
  172. [_manager cancelWithError:_error];
  173. }
  174. /** @fn testCancel
  175. @brief Tests cancelling the pending callbacks.
  176. */
  177. - (void)testCancel {
  178. // Set up timeout.
  179. XCTAssertGreaterThan(_manager.timeout, 0);
  180. _manager.timeout = kRegistrationTimeout;
  181. // Add callback to cancel.
  182. OCMExpect([_mockApplication registerForRemoteNotifications]);
  183. __block BOOL callbackCalled = NO;
  184. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  185. XCTAssertNil(token);
  186. XCTAssertEqualObjects(error, self->_error);
  187. XCTAssertFalse(callbackCalled); // verify callback is not called twice
  188. callbackCalled = YES;
  189. }];
  190. XCTAssertFalse(callbackCalled);
  191. // Call cancel.
  192. [_manager cancelWithError:_error];
  193. XCTAssertTrue(callbackCalled);
  194. // Add callback to timeout.
  195. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  196. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  197. XCTAssertNil(token);
  198. XCTAssertNil(error);
  199. [expectation fulfill];
  200. }];
  201. // Time out.
  202. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  203. OCMVerifyAll(_mockApplication);
  204. }
  205. /** @fn testLegacyRegistration
  206. @brief Tests remote notification registration on legacy systems.
  207. */
  208. - (void)testLegacyRegistration {
  209. // Use a custom class for `respondsToSelector:` to work.
  210. _mockApplication = OCMClassMock([FIRAuthLegacyUIApplication class]);
  211. _manager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:_mockApplication];
  212. // Add callback.
  213. #pragma clang diagnostic push
  214. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  215. [[[_mockApplication expect] ignoringNonObjectArgs] registerForRemoteNotificationTypes:0];
  216. #pragma clang diagnostic pop
  217. __block BOOL callbackCalled = NO;
  218. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  219. XCTAssertEqualObjects(token.data, self->_data);
  220. XCTAssertNotEqual(token.type, FIRAuthAPNSTokenTypeUnknown);
  221. XCTAssertNil(error);
  222. callbackCalled = YES;
  223. }];
  224. XCTAssertFalse(callbackCalled);
  225. // Set the token.
  226. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeUnknown];
  227. XCTAssertTrue(callbackCalled);
  228. // Verify the mock in the main thread.
  229. XCTestExpectation *expectation = [self expectationWithDescription:@"verify mock"];
  230. dispatch_async(dispatch_get_main_queue(), ^{
  231. OCMVerifyAll(self->_mockApplication);
  232. [expectation fulfill];
  233. });
  234. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  235. }
  236. @end
  237. NS_ASSUME_NONNULL_END
  238. #endif