FIRAuthAPNSTokenManagerTests.m 9.0 KB

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