FIRAuthAPNSTokenManagerTests.m 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
  33. /** @class FIRAuthLegacyUIApplication
  34. @brief A fake legacy (< iOS 7) UIApplication class.
  35. @remarks A custom class is needed because `respondsToSelector:` itself cannot be mocked.
  36. */
  37. @interface FIRAuthLegacyUIApplication : NSObject
  38. #pragma clang diagnostic push
  39. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  40. - (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types;
  41. #pragma clang diagnostic pop
  42. @end
  43. @implementation FIRAuthLegacyUIApplication
  44. #pragma clang diagnostic push
  45. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  46. - (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types {
  47. }
  48. #pragma clang diagnostic pop
  49. @end
  50. #endif // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
  51. /** @class FIRAuthAPNSTokenManagerTests
  52. @brief Unit tests for @c FIRAuthAPNSTokenManager .
  53. */
  54. @interface FIRAuthAPNSTokenManagerTests : XCTestCase
  55. @end
  56. @implementation FIRAuthAPNSTokenManagerTests {
  57. /** @var _mockApplication
  58. @brief The mock application for testing.
  59. */
  60. id _mockApplication;
  61. /** @var _manager
  62. @brief The @c FIRAuthAPNSTokenManager instance under tests.
  63. */
  64. FIRAuthAPNSTokenManager *_manager;
  65. /** @var _data
  66. @brief One piece of data used for testing.
  67. */
  68. NSData *_data;
  69. /** @var _otherData
  70. @brief Another piece of data used for testing.
  71. */
  72. NSData *_otherData;
  73. /** @var _error
  74. @brief The fake error used for testing.
  75. */
  76. NSError *_error;
  77. }
  78. - (void)setUp {
  79. _mockApplication = OCMClassMock([UIApplication class]);
  80. _manager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:_mockApplication];
  81. _data = [@"qwerty" dataUsingEncoding:NSUTF8StringEncoding];
  82. _otherData = [@"!@#$" dataUsingEncoding:NSUTF8StringEncoding];
  83. }
  84. /** @fn testSetToken
  85. @brief Tests setting and getting the `token` property.
  86. */
  87. - (void)testSetToken {
  88. XCTAssertNil(_manager.token);
  89. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeProd];
  90. XCTAssertEqualObjects(_manager.token.data, _data);
  91. XCTAssertEqual(_manager.token.type, FIRAuthAPNSTokenTypeProd);
  92. _manager.token = nil;
  93. XCTAssertNil(_manager.token);
  94. }
  95. /** @fn testDetectTokenType
  96. @brief Tests automatic detection of token type.
  97. */
  98. - (void)testDetectTokenType {
  99. XCTAssertNil(_manager.token);
  100. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeUnknown];
  101. XCTAssertEqualObjects(_manager.token.data, _data);
  102. XCTAssertNotEqual(_manager.token.type, FIRAuthAPNSTokenTypeUnknown);
  103. }
  104. /** @fn testCallback
  105. @brief Tests callbacks are called.
  106. */
  107. - (void)testCallback {
  108. // Add first callback, which is yet to be called.
  109. OCMExpect([_mockApplication registerForRemoteNotifications]);
  110. __block BOOL firstCallbackCalled = NO;
  111. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  112. XCTAssertEqualObjects(token.data, self->_data);
  113. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  114. XCTAssertNil(error);
  115. firstCallbackCalled = YES;
  116. }];
  117. XCTAssertFalse(firstCallbackCalled);
  118. // Add second callback, which is yet to be called either.
  119. __block BOOL secondCallbackCalled = NO;
  120. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  121. XCTAssertEqualObjects(token.data, self->_data);
  122. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  123. XCTAssertNil(error);
  124. secondCallbackCalled = YES;
  125. }];
  126. XCTAssertFalse(secondCallbackCalled);
  127. // Setting nil token shouldn't trigger either callbacks.
  128. _manager.token = nil;
  129. XCTAssertFalse(firstCallbackCalled);
  130. XCTAssertFalse(secondCallbackCalled);
  131. XCTAssertNil(_manager.token);
  132. // Setting a real token should trigger both callbacks.
  133. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeSandbox];
  134. XCTAssertTrue(firstCallbackCalled);
  135. XCTAssertTrue(secondCallbackCalled);
  136. XCTAssertEqualObjects(_manager.token.data, _data);
  137. XCTAssertEqual(_manager.token.type, FIRAuthAPNSTokenTypeSandbox);
  138. // Add third callback, which should be called back immediately.
  139. __block BOOL thirdCallbackCalled = NO;
  140. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  141. XCTAssertEqualObjects(token.data, self->_data);
  142. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeSandbox);
  143. XCTAssertNil(error);
  144. thirdCallbackCalled = YES;
  145. }];
  146. XCTAssertTrue(thirdCallbackCalled);
  147. // Verify the mock in the main thread.
  148. XCTestExpectation *expectation = [self expectationWithDescription:@"verify mock"];
  149. dispatch_async(dispatch_get_main_queue(), ^{
  150. OCMVerifyAll(self->_mockApplication);
  151. [expectation fulfill];
  152. });
  153. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  154. }
  155. /** @fn testTimeout
  156. @brief Tests callbacks can be timed out.
  157. */
  158. - (void)testTimeout {
  159. // Set up timeout.
  160. XCTAssertGreaterThan(_manager.timeout, 0);
  161. _manager.timeout = kRegistrationTimeout;
  162. // Add callback to time out.
  163. OCMExpect([_mockApplication registerForRemoteNotifications]);
  164. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  165. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  166. XCTAssertNil(token);
  167. XCTAssertNil(error);
  168. [expectation fulfill];
  169. }];
  170. // Time out.
  171. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  172. OCMVerifyAll(_mockApplication);
  173. // Calling cancel afterwards should have no effect.
  174. [_manager cancelWithError:_error];
  175. }
  176. /** @fn testCancel
  177. @brief Tests cancelling the pending callbacks.
  178. */
  179. - (void)testCancel {
  180. // Set up timeout.
  181. XCTAssertGreaterThan(_manager.timeout, 0);
  182. _manager.timeout = kRegistrationTimeout;
  183. // Add callback to cancel.
  184. OCMExpect([_mockApplication registerForRemoteNotifications]);
  185. __block BOOL callbackCalled = NO;
  186. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  187. XCTAssertNil(token);
  188. XCTAssertEqualObjects(error, self->_error);
  189. XCTAssertFalse(callbackCalled); // verify callback is not called twice
  190. callbackCalled = YES;
  191. }];
  192. XCTAssertFalse(callbackCalled);
  193. // Call cancel.
  194. [_manager cancelWithError:_error];
  195. XCTAssertTrue(callbackCalled);
  196. // Add callback to timeout.
  197. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  198. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  199. XCTAssertNil(token);
  200. XCTAssertNil(error);
  201. [expectation fulfill];
  202. }];
  203. // Time out.
  204. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  205. OCMVerifyAll(_mockApplication);
  206. }
  207. #if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
  208. /** @fn testLegacyRegistration
  209. @brief Tests remote notification registration on legacy systems.
  210. */
  211. - (void)testLegacyRegistration {
  212. // Use a custom class for `respondsToSelector:` to work.
  213. _mockApplication = OCMClassMock([FIRAuthLegacyUIApplication class]);
  214. _manager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:_mockApplication];
  215. // Add callback.
  216. #pragma clang diagnostic push
  217. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  218. [[[_mockApplication expect] ignoringNonObjectArgs] registerForRemoteNotificationTypes:0];
  219. #pragma clang diagnostic pop
  220. __block BOOL callbackCalled = NO;
  221. [_manager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, NSError *_Nullable error) {
  222. XCTAssertEqualObjects(token.data, self->_data);
  223. XCTAssertNotEqual(token.type, FIRAuthAPNSTokenTypeUnknown);
  224. XCTAssertNil(error);
  225. callbackCalled = YES;
  226. }];
  227. XCTAssertFalse(callbackCalled);
  228. // Set the token.
  229. _manager.token = [[FIRAuthAPNSToken alloc] initWithData:_data type:FIRAuthAPNSTokenTypeUnknown];
  230. XCTAssertTrue(callbackCalled);
  231. // Verify the mock in the main thread.
  232. XCTestExpectation *expectation = [self expectationWithDescription:@"verify mock"];
  233. dispatch_async(dispatch_get_main_queue(), ^{
  234. OCMVerifyAll(self->_mockApplication);
  235. [expectation fulfill];
  236. });
  237. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  238. }
  239. #endif // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
  240. @end
  241. NS_ASSUME_NONNULL_END
  242. #endif // TARGET_OS_IOS