diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index 7debc404cc0..829c7cdfad8 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -617,6 +617,7 @@ EDD53E2A211B08A300376BFF /* FIRComponentTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E28211B08A300376BFF /* FIRComponentTestUtilities.m */; }; EDD53E2B211B08A300376BFF /* FIRComponentTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E28211B08A300376BFF /* FIRComponentTestUtilities.m */; }; EDD53E2C211B08A300376BFF /* FIRComponentTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E28211B08A300376BFF /* FIRComponentTestUtilities.m */; }; + EDF5242C21EA37AA00BB24C6 /* FIRMessagingTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EDF5242B21EA364600BB24C6 /* FIRMessagingTestUtilities.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1345,6 +1346,8 @@ EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FIRAuthInteropFake.m; path = Shared/FIRAuthInteropFake.m; sourceTree = ""; }; EDD53E28211B08A300376BFF /* FIRComponentTestUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FIRComponentTestUtilities.m; path = Shared/FIRComponentTestUtilities.m; sourceTree = ""; }; EDD53E29211B08A300376BFF /* FIRComponentTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FIRComponentTestUtilities.h; path = Shared/FIRComponentTestUtilities.h; sourceTree = ""; }; + EDF5242A21EA364600BB24C6 /* FIRMessagingTestUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRMessagingTestUtilities.h; sourceTree = ""; }; + EDF5242B21EA364600BB24C6 /* FIRMessagingTestUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRMessagingTestUtilities.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2340,6 +2343,8 @@ DE9315D71E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.m */, DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */, DE9315D81E8738B70083EDBF /* Info.plist */, + EDF5242A21EA364600BB24C6 /* FIRMessagingTestUtilities.h */, + EDF5242B21EA364600BB24C6 /* FIRMessagingTestUtilities.m */, ); path = Tests; sourceTree = ""; @@ -4419,6 +4424,7 @@ DE9315F91E8738E60083EDBF /* FIRMessagingFakeConnection.m in Sources */, DE9316021E8738E60083EDBF /* FIRMessagingServiceTest.m in Sources */, DE9315FE1E8738E60083EDBF /* FIRMessagingRegistrarTest.m in Sources */, + EDF5242C21EA37AA00BB24C6 /* FIRMessagingTestUtilities.m in Sources */, DE9316031E8738E60083EDBF /* FIRMessagingSyncMessageManagerTest.m in Sources */, DE9315FF1E8738E60083EDBF /* FIRMessagingRemoteNotificationsProxyTest.m in Sources */, DEF61BFD216E8B1100A738D4 /* FIRMessagingReceiverTest.m in Sources */, diff --git a/Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m b/Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m index 33797a2f197..b8a2937e606 100644 --- a/Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m +++ b/Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m @@ -21,10 +21,12 @@ #import "FIRMessaging.h" #import "FIRMessagingConstants.h" #import "FIRMessagingTestNotificationUtilities.h" +#import "FIRMessagingTestUtilities.h" + +NSString *const kFIRMessagingTestsLinkHandlingSuiteName = @"com.messaging.test_linkhandling"; @interface FIRMessaging () -+ (FIRMessaging *)messagingForTests; - (NSURL *)linkURLFromMessage:(NSDictionary *)message; @end @@ -39,10 +41,13 @@ @implementation FIRMessagingLinkHandlingTest - (void)setUp { [super setUp]; - _messaging = [FIRMessaging messagingForTests]; + + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsLinkHandlingSuiteName]; + _messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults]; } - (void)tearDown { + [self.messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingTestsLinkHandlingSuiteName]; _messaging = nil; [super tearDown]; } diff --git a/Example/Messaging/Tests/FIRMessagingReceiverTest.m b/Example/Messaging/Tests/FIRMessagingReceiverTest.m index 02818b754b7..95e6dd9c497 100644 --- a/Example/Messaging/Tests/FIRMessagingReceiverTest.m +++ b/Example/Messaging/Tests/FIRMessagingReceiverTest.m @@ -22,10 +22,9 @@ #import "FIRMessaging.h" #import "FIRMessaging_Private.h" +#import "FIRMessagingTestUtilities.h" -@interface FIRMessaging () -+ (FIRMessaging *)messagingForTests; -@end +NSString *const kFIRMessagingTestsReceiverSuiteName = @"com.messaging.test_receiverTest"; @interface FIRMessagingReceiverTest : XCTestCase @property(nonatomic, readonly, strong) FIRMessaging *messaging; @@ -36,9 +35,15 @@ @implementation FIRMessagingReceiverTest - (void)setUp { [super setUp]; - _messaging = [FIRMessaging messagingForTests]; - [[NSUserDefaults standardUserDefaults] - removePersistentDomainForName:[NSBundle mainBundle].bundleIdentifier]; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsReceiverSuiteName]; + _messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults]; +} + +- (void)tearDown { + [self.messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingTestsReceiverSuiteName]; + _messaging = nil; + + [super tearDown]; } - (void)testUseMessagingDelegate { diff --git a/Example/Messaging/Tests/FIRMessagingServiceTest.m b/Example/Messaging/Tests/FIRMessagingServiceTest.m index bb447472951..65019806c66 100644 --- a/Example/Messaging/Tests/FIRMessagingServiceTest.m +++ b/Example/Messaging/Tests/FIRMessagingServiceTest.m @@ -22,6 +22,7 @@ #import "FIRMessaging.h" #import "FIRMessagingClient.h" #import "FIRMessagingPubSub.h" +#import "FIRMessagingTestUtilities.h" #import "FIRMessagingTopicsCommon.h" #import "InternalHeaders/FIRMessagingInternalUtilities.h" #import "NSError+FIRMessaging.h" @@ -31,8 +32,9 @@ @"yUTTzK6dhIvLqzqqCSabaa4TQVM0pGTmF6r7tmMHPe6VYiGMHuCwJFgj5v97xl78sUNMLwuPPhoci8z_" @"QGlCrTbxCFGzEUfvA3fGpGgIVQU2W6"; +NSString *const kFIRMessagingTestsServiceSuiteName = @"com.messaging.test_serviceTest"; + @interface FIRMessaging () -+ (FIRMessaging *)messagingForTests; @property(nonatomic, readwrite, strong) FIRMessagingClient *client; @property(nonatomic, readwrite, strong) FIRMessagingPubSub *pubsub; @property(nonatomic, readwrite, strong) NSString *defaultFcmToken; @@ -55,7 +57,8 @@ @interface FIRMessagingServiceTest : XCTestCase { @implementation FIRMessagingServiceTest - (void)setUp { - _messaging = [FIRMessaging messagingForTests]; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsServiceSuiteName]; + _messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults]; _messaging.defaultFcmToken = kFakeToken; _mockPubSub = OCMPartialMock(_messaging.pubsub); [_mockPubSub setClient:nil]; @@ -63,6 +66,8 @@ - (void)setUp { } - (void)tearDown { + [_messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingTestsServiceSuiteName]; + _messaging = nil; [_mockPubSub stopMocking]; [super tearDown]; } diff --git a/Example/Messaging/Tests/FIRMessagingTest.m b/Example/Messaging/Tests/FIRMessagingTest.m index 66357e8b102..3fb0477ff45 100644 --- a/Example/Messaging/Tests/FIRMessagingTest.m +++ b/Example/Messaging/Tests/FIRMessagingTest.m @@ -20,25 +20,22 @@ #import #import +#import #import "FIRMessaging.h" #import "FIRMessaging_Private.h" +#import "FIRMessagingTestUtilities.h" extern NSString *const kFIRMessagingFCMTokenFetchAPNSOption; -@interface FIRInstanceID (ExposedForTest) - -+ (FIRInstanceID *)instanceIDForTests; - -@end +/// The NSUserDefaults domain for testing. +NSString *const kFIRMessagingDefaultsTestDomain = @"com.messaging.tests"; @interface FIRMessaging () -+ (FIRMessaging *)messagingForTests; @property(nonatomic, readwrite, strong) NSString *defaultFcmToken; @property(nonatomic, readwrite, strong) NSData *apnsTokenData; @property(nonatomic, readwrite, strong) FIRInstanceID *instanceID; -@property(nonatomic, readwrite, strong) NSUserDefaults *messagingUserDefaults; // Direct Channel Methods - (void)updateAutomaticClientConnection; @@ -59,8 +56,12 @@ @implementation FIRMessagingTest - (void)setUp { [super setUp]; - _messaging = [FIRMessaging messagingForTests]; - _messaging.instanceID = [FIRInstanceID instanceIDForTests]; + + // Create the messaging instance with all the necessary dependencies. + NSUserDefaults *defaults = + [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingDefaultsTestDomain]; + _messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults]; + _mockFirebaseApp = OCMClassMock([FIRApp class]); OCMStub([_mockFirebaseApp defaultApp]).andReturn(_mockFirebaseApp); _mockInstanceID = OCMPartialMock(self.messaging.instanceID); @@ -69,12 +70,14 @@ - (void)setUp { } - (void)tearDown { + [self.messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingDefaultsTestDomain]; self.messaging.shouldEstablishDirectChannel = NO; self.messaging.defaultFcmToken = nil; self.messaging.apnsTokenData = nil; [_mockMessaging stopMocking]; [_mockInstanceID stopMocking]; [_mockFirebaseApp stopMocking]; + _messaging = nil; [super tearDown]; } diff --git a/Example/Messaging/Tests/FIRMessagingTestUtilities.h b/Example/Messaging/Tests/FIRMessagingTestUtilities.h new file mode 100644 index 00000000000..1226cd17c02 --- /dev/null +++ b/Example/Messaging/Tests/FIRMessagingTestUtilities.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRMessaging.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMessaging (TestUtilities) +// Surface the user defaults instance to clean up after tests. +@property(nonatomic, strong) NSUserDefaults *messagingUserDefaults; +@end + +@interface FIRMessagingTestUtilities : NSObject + +/** + Creates an instance of FIRMessaging to use with tests, and will instantiate a new instance of + InstanceID. + + Note: This does not create a FIRApp instance and call `configureWithApp:`. If required, it's up to + each test to do so. + + @param userDefaults The user defaults to be used for Messaging. + @return An instance of FIRMessaging with everything initialized. + */ ++ (FIRMessaging *)messagingForTestsWithUserDefaults:(NSUserDefaults *)userDefaults; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Messaging/Tests/FIRMessagingTestUtilities.m b/Example/Messaging/Tests/FIRMessagingTestUtilities.m new file mode 100644 index 00000000000..729587587c5 --- /dev/null +++ b/Example/Messaging/Tests/FIRMessagingTestUtilities.m @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRMessagingTestUtilities.h" + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstanceID (ExposedForTest) + +/// Private initializer to avoid singleton usage. +- (FIRInstanceID *)initPrivately; + +/// Starts fetching and configuration of InstanceID. This is necessary after the `initPrivately` +/// call. +- (void)start; + +@end + +@interface FIRMessaging (ExposedForTest) + +/// Surface internal initializer to avoid singleton usage during tests. +- (instancetype)initWithAnalytics:(nullable id)analytics + withInstanceID:(FIRInstanceID *)instanceID + withUserDefaults:(NSUserDefaults *)defaults; + +/// Kicks off required calls for some messaging tests. +- (void)start; + +@end + +@implementation FIRMessagingTestUtilities + ++ (FIRMessaging *)messagingForTestsWithUserDefaults:(NSUserDefaults *)userDefaults { + // Create the messaging instance with all the necessary dependencies. + FIRInstanceID *instanceID = [[FIRInstanceID alloc] initPrivately]; + [instanceID start]; + + // Create the messaging instance and call `start`. + FIRMessaging *messaging = [[FIRMessaging alloc] initWithAnalytics:nil + withInstanceID:instanceID + withUserDefaults:userDefaults]; + [messaging start]; + return messaging; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Messaging/FIRMessaging.m b/Firebase/Messaging/FIRMessaging.m index 7aa439191ed..57e1df55829 100644 --- a/Firebase/Messaging/FIRMessaging.m +++ b/Firebase/Messaging/FIRMessaging.m @@ -162,32 +162,19 @@ @interface FIRMessaging () @implementation FIRMessaging -// File static to support InstanceID tests that call [FIRMessaging messaging] after -// [FIRMessaging messagingForTests]. -static FIRMessaging *sMessaging; - + (FIRMessaging *)messaging { - if (sMessaging != nil) { - return sMessaging; - } FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here. - id messaging = + id instance = FIR_COMPONENT(FIRMessagingInstanceProvider, defaultApp.container); + // We know the instance coming from the container is a FIRMessaging instance, cast it and move on. + FIRMessaging *messaging = (FIRMessaging *)instance; + static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - [(FIRMessaging *)messaging start]; + [messaging start]; }); - sMessaging = (FIRMessaging *)messaging; - return sMessaging; -} - -+ (FIRMessaging *)messagingForTests { - sMessaging = [[FIRMessaging alloc] initWithAnalytics:nil - withInstanceID:[FIRInstanceID instanceID] - withUserDefaults:[NSUserDefaults standardUserDefaults]]; - [sMessaging start]; - return sMessaging; + return messaging; } - (instancetype)initWithAnalytics:(nullable id)analytics @@ -322,7 +309,7 @@ - (void)setupNotificationListeners { } - (void)setupReceiver { - self.receiver = [[FIRMessagingReceiver alloc] init]; + self.receiver = [[FIRMessagingReceiver alloc] initWithUserDefaults:self.messagingUserDefaults]; self.receiver.delegate = self; } diff --git a/Firebase/Messaging/FIRMessagingReceiver.h b/Firebase/Messaging/FIRMessagingReceiver.h index e312420449f..8b5aa585bc2 100644 --- a/Firebase/Messaging/FIRMessagingReceiver.h +++ b/Firebase/Messaging/FIRMessagingReceiver.h @@ -17,18 +17,28 @@ #import "FIRMessagingDataMessageManager.h" #import "FIRMessaging.h" +NS_ASSUME_NONNULL_BEGIN + @class FIRMessagingReceiver; @protocol FIRMessagingReceiverDelegate -- (void)receiver:(nonnull FIRMessagingReceiver *)receiver - receivedRemoteMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage; +- (void)receiver:(FIRMessagingReceiver *)receiver + receivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage; @end @interface FIRMessagingReceiver : NSObject +/// Default initializer for creating the messaging receiver. +- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER; + +/// Use `initWithUserDefaults:` instead. +- (instancetype)init NS_UNAVAILABLE; + @property(nonatomic, weak, nullable) id delegate; /// Whether to use direct channel for direct channel message callback handler in all iOS versions. @property(nonatomic, assign) BOOL useDirectChannel; @end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Messaging/FIRMessagingReceiver.m b/Firebase/Messaging/FIRMessagingReceiver.m index ac8a6837561..05e6a75bc13 100644 --- a/Firebase/Messaging/FIRMessagingReceiver.m +++ b/Firebase/Messaging/FIRMessagingReceiver.m @@ -36,8 +36,22 @@ static int downstreamMessageID = 0; +@interface FIRMessagingReceiver () +@property(nonatomic, strong) NSUserDefaults *defaults; +@end + @implementation FIRMessagingReceiver +#pragma mark - Initializer + +- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults { + self = [super init]; + if (self != nil) { + _defaults = defaults; + } + return self; +} + #pragma mark - FIRMessagingDataMessageManager protocol - (void)didReceiveMessage:(NSDictionary *)message withIdentifier:(nullable NSString *)messageID { @@ -152,9 +166,8 @@ + (NSString *)nextMessageID { - (BOOL)useDirectChannel { // Check storage - NSUserDefaults *messagingDefaults = [NSUserDefaults standardUserDefaults]; id shouldUseMessagingDelegate = - [messagingDefaults objectForKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate]; + [_defaults objectForKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate]; if (shouldUseMessagingDelegate) { return [shouldUseMessagingDelegate boolValue]; } @@ -170,12 +183,10 @@ - (BOOL)useDirectChannel { } - (void)setUseDirectChannel:(BOOL)useDirectChannel { - NSUserDefaults *messagingDefaults = [NSUserDefaults standardUserDefaults]; BOOL shouldUseMessagingDelegate = [self useDirectChannel]; if (useDirectChannel != shouldUseMessagingDelegate) { - [messagingDefaults setBool:useDirectChannel - forKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate]; - [messagingDefaults synchronize]; + [_defaults setBool:useDirectChannel forKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate]; + [_defaults synchronize]; } }