diff options
Diffstat (limited to 'Example')
-rw-r--r-- | Example/Core/Tests/FIRAnalyticsConfigurationTest.m | 100 | ||||
-rw-r--r-- | Example/Core/Tests/FIRAppTest.m | 104 | ||||
-rw-r--r-- | Example/Core/Tests/FIRComponentContainerTest.m | 157 | ||||
-rw-r--r-- | Example/Core/Tests/FIRComponentTypeTest.m | 60 | ||||
-rw-r--r-- | Example/Core/Tests/FIRLoggerTest.m | 22 | ||||
-rw-r--r-- | Example/Core/Tests/FIRTestComponents.h | 63 | ||||
-rw-r--r-- | Example/Core/Tests/FIRTestComponents.m | 118 | ||||
-rw-r--r-- | Example/Firebase.xcodeproj/project.pbxproj | 38 |
8 files changed, 583 insertions, 79 deletions
diff --git a/Example/Core/Tests/FIRAnalyticsConfigurationTest.m b/Example/Core/Tests/FIRAnalyticsConfigurationTest.m index a66ad06..8cf9da4 100644 --- a/Example/Core/Tests/FIRAnalyticsConfigurationTest.m +++ b/Example/Core/Tests/FIRAnalyticsConfigurationTest.m @@ -20,19 +20,25 @@ #import <FirebaseCore/FIRAnalyticsConfiguration.h> @interface FIRAnalyticsConfigurationTest : FIRTestCase -/// A mock for [NSNotificationCenter defaultCenter]. -@property(nonatomic, strong) id notificationCenterMock; +/// An observer for NSNotificationCenter. +@property(nonatomic, strong) id observerMock; + +@property(nonatomic, strong) NSNotificationCenter *notificationCenter; @end @implementation FIRAnalyticsConfigurationTest - (void)setUp { [super setUp]; - _notificationCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]); + + _observerMock = OCMObserverMock(); + _notificationCenter = [NSNotificationCenter defaultCenter]; } - (void)tearDown { - [_notificationCenterMock stopMocking]; + _observerMock = nil; + _notificationCenter = nil; + [super tearDown]; } @@ -44,49 +50,73 @@ /// Test that setting the minimum session interval on the singleton fires a notification. - (void)testMinimumSessionIntervalNotification { + // Pick a value to set as the session interval and verify it's in the userInfo dictionary of the + // posted notification. + NSNumber *sessionInterval = @2601; + + // Set up the expectation for the notification. FIRAnalyticsConfiguration *config = [FIRAnalyticsConfiguration sharedInstance]; - [config setMinimumSessionInterval:2601]; NSString *notificationName = kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification; - OCMVerify([self.notificationCenterMock postNotificationName:notificationName - object:config - userInfo:@{ - notificationName : @2601 - }]); + [self expectNotificationForObserver:self.observerMock + notificationName:notificationName + object:config + userInfo:@{notificationName : sessionInterval}]; + + // Trigger the notification. + [config setMinimumSessionInterval:[sessionInterval integerValue]]; + + // Verify the observer mock. + OCMVerifyAll(self.observerMock); } /// Test that setting the minimum session timeout interval on the singleton fires a notification. - (void)testSessionTimeoutIntervalNotification { + // Pick a value to set as the timeout interval and verify it's in the userInfo dictionary of the + // posted notification. + NSNumber *timeoutInterval = @1000; + + // Set up the expectation for the notification. FIRAnalyticsConfiguration *config = [FIRAnalyticsConfiguration sharedInstance]; - [config setSessionTimeoutInterval:1000]; NSString *notificationName = kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification; - OCMVerify([self.notificationCenterMock postNotificationName:notificationName - object:config - userInfo:@{ - notificationName : @1000 - }]); + [self expectNotificationForObserver:self.observerMock + notificationName:notificationName + object:config + userInfo:@{notificationName : timeoutInterval}]; + + // Trigger the notification. + [config setSessionTimeoutInterval:[timeoutInterval integerValue]]; + + /// Verify the observer mock. + OCMVerifyAll(self.observerMock); } - (void)testSettingAnalyticsCollectionEnabled { - // The ordering matters for these notifications. - [self.notificationCenterMock setExpectationOrderMatters:YES]; - - // Test setting to enabled. + // Test setting to enabled. The ordering matters for these notifications. FIRAnalyticsConfiguration *config = [FIRAnalyticsConfiguration sharedInstance]; NSString *notificationName = kFIRAnalyticsConfigurationSetEnabledNotification; + [self.notificationCenter addMockObserver:self.observerMock name:notificationName object:config]; + + [self.observerMock setExpectationOrderMatters:YES]; + [[self.observerMock expect] notificationWithName:notificationName + object:config + userInfo:@{ + notificationName : @YES + }]; + + // Test setting to enabled. [config setAnalyticsCollectionEnabled:YES]; - OCMVerify([self.notificationCenterMock postNotificationName:notificationName - object:config - userInfo:@{ - notificationName : @YES - }]); + + // Expect the second notification. + [[self.observerMock expect] notificationWithName:notificationName + object:config + userInfo:@{ + notificationName : @NO + }]; // Test setting to disabled. [config setAnalyticsCollectionEnabled:NO]; - OCMVerify([self.notificationCenterMock postNotificationName:notificationName - object:config - userInfo:@{ - notificationName : @NO - }]); + + OCMVerifyAll(self.observerMock); } - (void)testSettingAnalyticsCollectionPersistence { @@ -114,4 +144,14 @@ [userDefaultsMock stopMocking]; } +#pragma mark - Private Test Helpers + +- (void)expectNotificationForObserver:(id)observer + notificationName:(NSNotificationName)name + object:(nullable id)object + userInfo:(nullable NSDictionary *)userInfo { + [self.notificationCenter addMockObserver:self.observerMock name:name object:object]; + [[observer expect] notificationWithName:name object:object userInfo:userInfo]; +} + @end diff --git a/Example/Core/Tests/FIRAppTest.m b/Example/Core/Tests/FIRAppTest.m index 549c1ab..656f046 100644 --- a/Example/Core/Tests/FIRAppTest.m +++ b/Example/Core/Tests/FIRAppTest.m @@ -52,8 +52,9 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; @property(nonatomic) id appClassMock; @property(nonatomic) id optionsInstanceMock; -@property(nonatomic) id notificationCenterMock; +@property(nonatomic) id observerMock; @property(nonatomic) FIRApp *app; +@property(nonatomic) NSNotificationCenter *notificationCenter; @end @@ -65,13 +66,19 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; [FIRApp resetApps]; _appClassMock = OCMClassMock([FIRApp class]); _optionsInstanceMock = OCMPartialMock([FIROptions defaultOptions]); - _notificationCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]); + _observerMock = OCMObserverMock(); + + // TODO: Remove all usages of defaultCenter in Core, then we can instantiate an instance here to + // inject instead of using defaultCenter. + _notificationCenter = [NSNotificationCenter defaultCenter]; } - (void)tearDown { [_appClassMock stopMocking]; [_optionsInstanceMock stopMocking]; - [_notificationCenterMock stopMocking]; + [_notificationCenter removeObserver:_observerMock]; + _observerMock = nil; + _notificationCenter = nil; [super tearDown]; } @@ -79,11 +86,12 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; - (void)testConfigure { NSDictionary *expectedUserInfo = [self expectedUserInfoWithAppName:kFIRDefaultAppName isDefaultApp:YES]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo]); + [self expectNotificationForObserver:self.observerMock + notificationName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo]; XCTAssertNoThrow([FIRApp configure]); - OCMVerifyAll(self.notificationCenterMock); + OCMVerifyAll(self.observerMock); self.app = [FIRApp defaultApp]; XCTAssertNotNil(self.app); @@ -108,12 +116,13 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; NSDictionary *expectedUserInfo = [self expectedUserInfoWithAppName:kFIRDefaultAppName isDefaultApp:YES]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo]); + [self expectNotificationForObserver:self.observerMock + notificationName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo]; // default options XCTAssertNoThrow([FIRApp configureWithOptions:[FIROptions defaultOptions]]); - OCMVerifyAll(self.notificationCenterMock); + OCMVerifyAll(self.observerMock); self.app = [FIRApp defaultApp]; XCTAssertNotNil(self.app); @@ -130,12 +139,13 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; options.APIKey = kCustomizedAPIKey; NSDictionary *expectedUserInfo = [self expectedUserInfoWithAppName:kFIRDefaultAppName isDefaultApp:YES]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo]); + [self expectNotificationForObserver:self.observerMock + notificationName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo]; XCTAssertNoThrow([FIRApp configureWithOptions:options]); - OCMVerifyAll(self.notificationCenterMock); + OCMVerifyAll(self.observerMock); self.app = [FIRApp defaultApp]; XCTAssertNotNil(self.app); @@ -158,11 +168,12 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; NSDictionary *expectedUserInfo = [self expectedUserInfoWithAppName:kFIRTestAppName1 isDefaultApp:NO]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo]); + [self expectNotificationForObserver:self.observerMock + notificationName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo]; XCTAssertNoThrow([FIRApp configureWithName:kFIRTestAppName1 options:[FIROptions defaultOptions]]); - OCMVerifyAll(self.notificationCenterMock); + OCMVerifyAll(self.observerMock); XCTAssertTrue([FIRApp allApps].count == 1); self.app = [FIRApp appNamed:kFIRTestAppName1]; @@ -179,11 +190,16 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; FIROptions *newOptions = [options copy]; newOptions.deepLinkURLScheme = kDeepLinkURLScheme; + // Set up notification center observer for verifying notifications. + [self.notificationCenter addMockObserver:self.observerMock + name:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class]]; + NSDictionary *expectedUserInfo1 = [self expectedUserInfoWithAppName:kFIRTestAppName1 isDefaultApp:NO]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo1]); + [[self.observerMock expect] notificationWithName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo1]; XCTAssertNoThrow([FIRApp configureWithName:kFIRTestAppName1 options:newOptions]); XCTAssertTrue([FIRApp allApps].count == 1); self.app = [FIRApp appNamed:kFIRTestAppName1]; @@ -196,11 +212,13 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; NSDictionary *expectedUserInfo2 = [self expectedUserInfoWithAppName:kFIRTestAppName2 isDefaultApp:NO]; - OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification - object:[FIRApp class] - userInfo:expectedUserInfo2]); + [[self.observerMock expect] notificationWithName:kFIRAppReadyToConfigureSDKNotification + object:[FIRApp class] + userInfo:expectedUserInfo2]; + + [self.observerMock setExpectationOrderMatters:YES]; XCTAssertNoThrow([FIRApp configureWithName:kFIRTestAppName2 options:customizedOptions]); - OCMVerifyAll(self.notificationCenterMock); + OCMVerifyAll(self.observerMock); XCTAssertTrue([FIRApp allApps].count == 2); self.app = [FIRApp appNamed:kFIRTestAppName2]; @@ -241,12 +259,15 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; [FIRApp configure]; self.app = [FIRApp defaultApp]; XCTAssertTrue([FIRApp allApps].count == 1); + [self expectNotificationForObserver:self.observerMock + notificationName:kFIRAppDeleteNotification + object:[FIRApp class] + userInfo:[OCMArg any]]; [self.app deleteApp:^(BOOL success) { XCTAssertTrue(success); }]; - OCMVerify([self.notificationCenterMock postNotificationName:kFIRAppDeleteNotification - object:[FIRApp class] - userInfo:[OCMArg any]]); + + OCMVerifyAll(self.observerMock); XCTAssertTrue(self.app.alreadySentDeleteNotification); XCTAssertTrue([FIRApp allApps].count == 0); } @@ -671,16 +692,27 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; - (void)testGlobalDataCollectionNoDiagnosticsSent { [FIRApp configure]; + // Add an observer for the diagnostics notification - both with and without an object to ensure it + // catches it either way. Currently no object is sent, but in the future that could change. + [self.notificationCenter addMockObserver:self.observerMock + name:kFIRAppDiagnosticsNotification + object:nil]; + [self.notificationCenter addMockObserver:self.observerMock + name:kFIRAppDiagnosticsNotification + object:OCMOCK_ANY]; + // Stub out reading from user defaults since stubbing out the BOOL has issues. If the data // collection switch is disabled, the `sendLogs` call should return immediately and not fire a // notification. OCMStub([self.appClassMock readDataCollectionSwitchFromUserDefaultsForApp:OCMOCK_ANY]) .andReturn(@NO); - OCMReject([self.notificationCenterMock postNotificationName:kFIRAppDiagnosticsNotification - object:OCMOCK_ANY - userInfo:OCMOCK_ANY]); + NSError *error = [NSError errorWithDomain:@"com.firebase" code:42 userInfo:nil]; [[FIRApp defaultApp] sendLogsWithServiceName:@"Service" version:@"Version" error:error]; + + // The observer mock is strict and will raise an exception when an unexpected notification is + // received. + OCMVerifyAll(self.observerMock); } #pragma mark - Analytics Flag Tests @@ -767,6 +799,14 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; #pragma mark - private +- (void)expectNotificationForObserver:(id)observer + notificationName:(NSNotificationName)name + object:(nullable id)object + userInfo:(nullable NSDictionary *)userInfo { + [self.notificationCenter addMockObserver:observer name:name object:object]; + [[observer expect] notificationWithName:name object:object userInfo:userInfo]; +} + - (NSDictionary<NSString *, NSObject *> *)expectedUserInfoWithAppName:(NSString *)name isDefaultApp:(BOOL)isDefaultApp { return @{ diff --git a/Example/Core/Tests/FIRComponentContainerTest.m b/Example/Core/Tests/FIRComponentContainerTest.m new file mode 100644 index 0000000..b255973 --- /dev/null +++ b/Example/Core/Tests/FIRComponentContainerTest.m @@ -0,0 +1,157 @@ +// Copyright 2018 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 "FIRTestCase.h" + +#import <FirebaseCore/FIRAppInternal.h> +#import <FirebaseCore/FIRComponent.h> +#import <FirebaseCore/FIRComponentContainerInternal.h> + +#import "FIRTestComponents.h" + +/// Internally exposed methods and properties for testing. +@interface FIRComponentContainer (TestInternal) + +@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRComponentCreationBlock> *components; +@property(nonatomic, strong) NSMutableDictionary<NSString *, id> *cachedInstances; + ++ (void)registerAsComponentRegistrant:(Class)klass inSet:(NSMutableSet<Class> *)allRegistrants; + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet<Class> *)allRegistrants; + +@end + +@interface FIRComponentContainerTest : FIRTestCase + +@end + +@implementation FIRComponentContainerTest + +#pragma mark - Registration Tests + +- (void)testRegisteringConformingClass { + NSMutableSet<Class> *allRegistrants = [NSMutableSet<Class> set]; + Class testClass = [FIRTestClass class]; + [FIRComponentContainer registerAsComponentRegistrant:testClass inSet:allRegistrants]; + XCTAssertTrue([allRegistrants containsObject:testClass]); +} + +- (void)testRegisteringNonConformingClass { + NSMutableSet<Class> *allRegistrants = [NSMutableSet<Class> set]; + XCTAssertThrows( + [FIRComponentContainer registerAsComponentRegistrant:[NSString class] inSet:allRegistrants]); + XCTAssertTrue(allRegistrants.count == 0); +} + +- (void)testComponentsPopulatedOnInit { + FIRComponentContainer *container = [self containerWithRegistrants:@[ [FIRTestClass class] ]]; + + // Verify that the block is stored. + NSString *protocolName = NSStringFromProtocol(@protocol(FIRTestProtocol)); + FIRComponentCreationBlock creationBlock = container.components[protocolName]; + OCMExpect(creationBlock); +} + +#pragma mark - Caching Tests + +- (void)testInstanceCached { + FIRComponentContainer *container = + [self containerWithRegistrants:@[ [FIRTestClassCached class] ]]; + + // Fetch an instance for `FIRTestProtocolCached`, then fetch it again to assert it's cached. + id<FIRTestProtocolCached> instance1 = FIR_COMPONENT(FIRTestProtocolCached, container); + XCTAssertNotNil(instance1); + id<FIRTestProtocolCached> instance2 = FIR_COMPONENT(FIRTestProtocolCached, container); + XCTAssertNotNil(instance2); + XCTAssertEqual(instance1, instance2); +} + +- (void)testInstanceNotCached { + FIRComponentContainer *container = [self containerWithRegistrants:@[ [FIRTestClass class] ]]; + + // Retrieve an instance from the container, then fetch it again and ensure it's not the same + // instance. + id<FIRTestProtocol> instance1 = FIR_COMPONENT(FIRTestProtocol, container); + XCTAssertNotNil(instance1); + id<FIRTestProtocol> instance2 = FIR_COMPONENT(FIRTestProtocol, container); + XCTAssertNotNil(instance2); + XCTAssertNotEqual(instance1, instance2); +} + +- (void)testRemoveAllCachedInstances { + FIRComponentContainer *container = [self containerWithRegistrants:@[ + [FIRTestClass class], [FIRTestClassCached class], [FIRTestClassEagerCached class] + ]]; + + // Retrieve an instance of FIRTestClassCached to ensure it's cached. + id<FIRTestProtocolCached> cachedInstance1 = FIR_COMPONENT(FIRTestProtocolCached, container); + id<FIRTestProtocolEagerCached> eagerInstance1 = + FIR_COMPONENT(FIRTestProtocolEagerCached, container); + + // FIRTestClassEagerCached and FIRTestClassCached instances should be cached at this point. + XCTAssertTrue(container.cachedInstances.count == 2); + + // Remove the instances and verify cachedInstances is empty, and that new instances returned from + // the container don't match the old ones. + [container removeAllCachedInstances]; + XCTAssertTrue(container.cachedInstances.count == 0); + + id<FIRTestProtocolCached> cachedInstance2 = FIR_COMPONENT(FIRTestProtocolCached, container); + XCTAssertNotEqual(cachedInstance1, cachedInstance2); + id<FIRTestProtocolEagerCached> eagerInstance2 = + FIR_COMPONENT(FIRTestProtocolEagerCached, container); + XCTAssertNotEqual(eagerInstance1, eagerInstance2); +} + +#pragma mark - Instantiation Tests + +- (void)testEagerInstantiation { + // Create a container with `FIRTestClassEagerCached` as a registrant, which provides the + // implementation for `FIRTestProtocolEagerCached` and requires eager instantiation as well as + // caching so the test can verify it was eagerly instantiated. + FIRComponentContainer *container = + [self containerWithRegistrants:@[ [FIRTestClassEagerCached class] ]]; + NSString *protocolName = NSStringFromProtocol(@protocol(FIRTestProtocolEagerCached)); + XCTAssertNotNil(container.cachedInstances[protocolName]); +} + +#pragma mark - Input Validation Tests + +- (void)testProtocolAlreadyRegistered { + // Register two classes that provide the same protocol. Only one should be stored, and there + // should be a log stating that the protocol has already been registered. Right now there's no + // guarantee which one will be registered first since it's an NSSet under the hood, but that could + // change in the future. + // TODO(wilsonryan): Assert that the log gets called warning that it's already been registered. + FIRComponentContainer *container = + [self containerWithRegistrants:@[ [FIRTestClass class], [FIRTestClassDuplicate class] ]]; + XCTAssert(container.components.count == 1); +} + +#pragma mark - Convenience Methods + +/// Create a container that has registered the test class. +- (FIRComponentContainer *)containerWithRegistrants:(NSArray<Class> *)registrants { + id appMock = OCMClassMock([FIRApp class]); + NSMutableSet<Class> *allRegistrants = [NSMutableSet<Class> set]; + + // Initialize the container with the test classes. + for (Class c in registrants) { + [FIRComponentContainer registerAsComponentRegistrant:c inSet:allRegistrants]; + } + + return [[FIRComponentContainer alloc] initWithApp:appMock registrants:allRegistrants]; +} + +@end diff --git a/Example/Core/Tests/FIRComponentTypeTest.m b/Example/Core/Tests/FIRComponentTypeTest.m new file mode 100644 index 0000000..7076fdd --- /dev/null +++ b/Example/Core/Tests/FIRComponentTypeTest.m @@ -0,0 +1,60 @@ +// Copyright 2018 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 "FIRTestCase.h" + +#import <FirebaseCore/FIRComponentContainerInternal.h> +#import <FirebaseCore/FIRComponentType.h> + +#import "FIRTestComponents.h" + +@interface FIRComponentTypeTest : FIRTestCase + +@property(nonatomic, strong) id componentContainerMock; +@end + +@implementation FIRComponentTypeTest + +- (void)setUp { + [super setUp]; + _componentContainerMock = OCMClassMock([FIRComponentContainer class]); +} + +- (void)tearDown { + [super tearDown]; + [_componentContainerMock stopMocking]; +} + +- (void)testForwardsCallToContainer { + Protocol *testProtocol = @protocol(FIRTestProtocol); + OCMExpect([self.componentContainerMock instanceForProtocol:testProtocol]); + + // Grab an instance from the container, through ComponentType. + __unused id<FIRTestProtocol> instance = + [FIRComponentType<id<FIRTestProtocol>> instanceForProtocol:@protocol(FIRTestProtocol) + inContainer:self.componentContainerMock]; + OCMVerifyAll(self.componentContainerMock); +} + +- (void)testMacroForwardsCallToContainer { + Protocol *testProtocol = @protocol(FIRTestProtocol); + OCMExpect([self.componentContainerMock instanceForProtocol:testProtocol]); + + // Grab an instance from the container, through the macro that uses FIRComponentType. + __unused id<FIRTestProtocol> instance = + FIR_COMPONENT(FIRTestProtocol, self.componentContainerMock); + + OCMVerifyAll(self.componentContainerMock); +} +@end diff --git a/Example/Core/Tests/FIRLoggerTest.m b/Example/Core/Tests/FIRLoggerTest.m index c1ba37b..b871244 100644 --- a/Example/Core/Tests/FIRLoggerTest.m +++ b/Example/Core/Tests/FIRLoggerTest.m @@ -31,6 +31,8 @@ extern const char *kFIRLoggerASLClientFacilityName; extern void FIRResetLogger(void); +extern void FIRSetLoggerUserDefaults(NSUserDefaults *defaults); + extern aslclient getFIRLoggerClient(void); extern dispatch_queue_t getFIRClientQueue(void); @@ -43,7 +45,7 @@ static NSString *const kMessageCode = @"I-COR000001"; @property(nonatomic) NSString *randomLogString; -@property(nonatomic, strong) id userDefaultsMock; +@property(nonatomic, strong) NSUserDefaults *defaults; @end @@ -53,14 +55,15 @@ static NSString *const kMessageCode = @"I-COR000001"; [super setUp]; FIRResetLogger(); - // Stub NSUserDefaults for tracking the error and warning count. - _userDefaultsMock = OCMPartialMock([NSUserDefaults standardUserDefaults]); + // Stub NSUserDefaults for cleaner testing. + _defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.firebase.logger_test"]; + FIRSetLoggerUserDefaults(_defaults); } - (void)tearDown { [super tearDown]; - [_userDefaultsMock stopMocking]; + _defaults = nil; } // Test some stable variables to make sure they weren't accidently changed. @@ -92,8 +95,7 @@ static NSString *const kMessageCode = @"I-COR000001"; FIRLogError(kFIRLoggerCore, kMessageCode, @"Some error."); // Assert. - NSNumber *debugMode = - [[NSUserDefaults standardUserDefaults] objectForKey:kFIRPersistedDebugModeKey]; + NSNumber *debugMode = [self.defaults objectForKey:kFIRPersistedDebugModeKey]; XCTAssertNil(debugMode); XCTAssertFalse(getFIRLoggerDebugMode()); @@ -111,8 +113,7 @@ static NSString *const kMessageCode = @"I-COR000001"; FIRLogError(kFIRLoggerCore, kMessageCode, @"Some error."); // Assert. - NSNumber *debugMode = - [[NSUserDefaults standardUserDefaults] objectForKey:kFIRPersistedDebugModeKey]; + NSNumber *debugMode = [self.defaults objectForKey:kFIRPersistedDebugModeKey]; XCTAssertTrue(debugMode.boolValue); XCTAssertTrue(getFIRLoggerDebugMode()); @@ -123,14 +124,13 @@ static NSString *const kMessageCode = @"I-COR000001"; - (void)testInitializeASLForDebugModeWithUserDefaults { // Stub. NSNumber *debugMode = @YES; - OCMStub([self.userDefaultsMock boolForKey:kFIRPersistedDebugModeKey]) - .andReturn(debugMode.boolValue); + [self.defaults setBool:debugMode.boolValue forKey:kFIRPersistedDebugModeKey]; // Test. FIRLogError(kFIRLoggerCore, kMessageCode, @"Some error."); // Assert. - debugMode = [[NSUserDefaults standardUserDefaults] objectForKey:kFIRPersistedDebugModeKey]; + debugMode = [self.defaults objectForKey:kFIRPersistedDebugModeKey]; XCTAssertTrue(debugMode.boolValue); XCTAssertTrue(getFIRLoggerDebugMode()); } diff --git a/Example/Core/Tests/FIRTestComponents.h b/Example/Core/Tests/FIRTestComponents.h new file mode 100644 index 0000000..63b2075 --- /dev/null +++ b/Example/Core/Tests/FIRTestComponents.h @@ -0,0 +1,63 @@ +// Copyright 2018 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 <Foundation/Foundation.h> + +#import <FirebaseCore/FIRComponent.h> +#import <FirebaseCore/FIRComponentContainer.h> +#import <FirebaseCore/FIRComponentRegistrant.h> + +@protocol FIRComponentRegistrant; + +#pragma mark - Standard Component + +/// A test protocol to be used for container testing. +@protocol FIRTestProtocol +- (void)doSomething; +@end + +/// A test class that is a component registrant. +@interface FIRTestClass + : NSObject <FIRTestProtocol, FIRComponentRegistrant, FIRComponentLifecycleMaintainer> +@end + +/// A test class that is a component registrant, a duplicate of FIRTestClass. +@interface FIRTestClassDuplicate + : NSObject <FIRTestProtocol, FIRComponentRegistrant, FIRComponentLifecycleMaintainer> +@end + +#pragma mark - Eager Component + +/// A test protocol to be used for container testing. +@protocol FIRTestProtocolEagerCached +- (void)doSomethingFaster; +@end + +/// A test class that is a component registrant that provides a component requiring eager +/// instantiation, and is cached for easier validation that it was instantiated. +@interface FIRTestClassEagerCached + : NSObject <FIRTestProtocolEagerCached, FIRComponentRegistrant, FIRComponentLifecycleMaintainer> +@end + +#pragma mark - Cached Component + +/// A test protocol to be used for container testing. +@protocol FIRTestProtocolCached +@end + +/// A test class that is a component registrant that provides a component that requests to be +/// cached. +@interface FIRTestClassCached + : NSObject <FIRTestProtocolCached, FIRComponentRegistrant, FIRComponentLifecycleMaintainer> +@end diff --git a/Example/Core/Tests/FIRTestComponents.m b/Example/Core/Tests/FIRTestComponents.m new file mode 100644 index 0000000..68346f3 --- /dev/null +++ b/Example/Core/Tests/FIRTestComponents.m @@ -0,0 +1,118 @@ +// Copyright 2018 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 "FIRTestComponents.h" + +#import <FirebaseCore/FIRComponent.h> + +#pragma mark - Standard Component + +@implementation FIRTestClass + +/// FIRTestProtocol conformance. +- (void)doSomething { +} + +/// FIRComponentRegistrant conformance. ++ (nonnull NSArray<FIRComponent *> *)componentsToRegister { + FIRComponent *testComponent = + [FIRComponent componentWithProtocol:@protocol(FIRTestProtocol) + creationBlock:^id _Nullable(FIRComponentContainer *_Nonnull container, + BOOL *_Nonnull isCacheable) { + return [[FIRTestClass alloc] init]; + }]; + return @[ testComponent ]; +} + +/// FIRComponentLifecycleMaintainer conformance. +- (void)appWillBeDeleted:(FIRApp *)app { +} + +@end + +/// A test class that is a component registrant, a duplicate of FIRTestClass. +@implementation FIRTestClassDuplicate + +- (void)doSomething { +} + +/// FIRComponentRegistrant conformance. ++ (nonnull NSArray<FIRComponent *> *)componentsToRegister { + FIRComponent *testComponent = + [FIRComponent componentWithProtocol:@protocol(FIRTestProtocol) + creationBlock:^id _Nullable(FIRComponentContainer *_Nonnull container, + BOOL *_Nonnull isCacheable) { + return [[FIRTestClassDuplicate alloc] init]; + }]; + return @[ testComponent ]; +} + +/// FIRComponentLifecycleMaintainer conformance. +- (void)appWillBeDeleted:(FIRApp *)app { +} + +@end + +#pragma mark - Eager Component + +@implementation FIRTestClassEagerCached + +/// FIRTestProtocolEager conformance. +- (void)doSomethingFaster { +} + +/// FIRComponentRegistrant conformance. ++ (nonnull NSArray<FIRComponent *> *)componentsToRegister { + FIRComponent *testComponent = [FIRComponent + componentWithProtocol:@protocol(FIRTestProtocolEagerCached) + instantiationTiming:FIRInstantiationTimingAlwaysEager + dependencies:@[] + creationBlock:^id _Nullable(FIRComponentContainer *_Nonnull container, + BOOL *_Nonnull isCacheable) { + FIRTestClassEagerCached *instance = [[FIRTestClassEagerCached alloc] init]; + *isCacheable = YES; + [instance doSomethingFaster]; + return instance; + }]; + return @[ testComponent ]; +} + +/// FIRComponentLifecycleMaintainer conformance. +- (void)appWillBeDeleted:(FIRApp *)app { +} + +@end + +#pragma mark - Cached Component + +@implementation FIRTestClassCached + +/// FIRComponentRegistrant conformance. ++ (nonnull NSArray<FIRComponent *> *)componentsToRegister { + FIRComponent *testComponent = [FIRComponent + componentWithProtocol:@protocol(FIRTestProtocolCached) + creationBlock:^id _Nullable(FIRComponentContainer *_Nonnull container, + BOOL *_Nonnull isCacheable) { + FIRTestClassCached *instanceToCache = [[FIRTestClassCached alloc] init]; + *isCacheable = YES; + return instanceToCache; + }]; + return @[ testComponent ]; +} + +/// FIRComponentLifecycleMaintainer conformance. +- (void)appWillBeDeleted:(FIRApp *)app { +} + +@end diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index 61c4c6a..8d3c13b 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -568,6 +568,15 @@ DEF6C33D1FBCE775005D0740 /* FIRVerifyPasswordRequestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151F1E86C6FF0083EDBF /* FIRVerifyPasswordRequestTest.m */; }; DEF6C33E1FBCE775005D0740 /* FIRVerifyPasswordResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315201E86C6FF0083EDBF /* FIRVerifyPasswordResponseTests.m */; }; DEF6C3411FBCE775005D0740 /* OCMStubRecorder+FIRAuthUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315241E86C6FF0083EDBF /* OCMStubRecorder+FIRAuthUnitTests.m */; }; + ED34CF4E20DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4A20DC16DC000EA5D1 /* FIRComponentContainerTest.m */; }; + ED34CF4F20DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4A20DC16DC000EA5D1 /* FIRComponentContainerTest.m */; }; + ED34CF5020DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4A20DC16DC000EA5D1 /* FIRComponentContainerTest.m */; }; + ED34CF5120DC16DD000EA5D1 /* FIRTestComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4B20DC16DC000EA5D1 /* FIRTestComponents.m */; }; + ED34CF5220DC16DD000EA5D1 /* FIRTestComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4B20DC16DC000EA5D1 /* FIRTestComponents.m */; }; + ED34CF5320DC16DD000EA5D1 /* FIRTestComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4B20DC16DC000EA5D1 /* FIRTestComponents.m */; }; + ED34CF5420DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4D20DC16DD000EA5D1 /* FIRComponentTypeTest.m */; }; + ED34CF5520DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4D20DC16DD000EA5D1 /* FIRComponentTypeTest.m */; }; + ED34CF5620DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED34CF4D20DC16DD000EA5D1 /* FIRComponentTypeTest.m */; }; ED8C81002088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */; }; ED8C81012088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */; }; ED8C81022088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */; }; @@ -1255,6 +1264,10 @@ DEE14D7D1E844677006FA992 /* Tests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; }; DEF288401F9AB6E100D480CF /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; }; E2C2834C90DBAB56D568189F /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; }; + ED34CF4A20DC16DC000EA5D1 /* FIRComponentContainerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRComponentContainerTest.m; sourceTree = "<group>"; }; + ED34CF4B20DC16DC000EA5D1 /* FIRTestComponents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRTestComponents.m; sourceTree = "<group>"; }; + ED34CF4C20DC16DD000EA5D1 /* FIRTestComponents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRTestComponents.h; sourceTree = "<group>"; }; + ED34CF4D20DC16DD000EA5D1 /* FIRComponentTypeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRComponentTypeTest.m; sourceTree = "<group>"; }; ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRMutableDictionaryTest.m; sourceTree = "<group>"; }; ED8C80FB2088EFA10093EB8A /* FIRNetworkTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRNetworkTest.m; sourceTree = "<group>"; }; ED8C80FC2088EFA20093EB8A /* FIRReachabilityCheckerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRReachabilityCheckerTest.m; sourceTree = "<group>"; }; @@ -2265,21 +2278,25 @@ DEE14D741E844677006FA992 /* Tests */ = { isa = PBXGroup; children = ( - ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */, - ED8C80FB2088EFA10093EB8A /* FIRNetworkTest.m */, - ED8C80FC2088EFA20093EB8A /* FIRReachabilityCheckerTest.m */, - ED8C80FD2088EFA20093EB8A /* third_party */, EDD43AA320BF7C7B005EBB36 /* FIRAnalyticsConfigurationTest.m */, - DE4B26DE20855F1F0030A38C /* FIRAppEnvironmentUtilTest.m */, - DEE14D7B1E844677006FA992 /* FIRTestCase.h */, DEE14D751E844677006FA992 /* FIRAppAssociationRegistrationUnitTests.m */, + DE4B26DE20855F1F0030A38C /* FIRAppEnvironmentUtilTest.m */, DEE14D761E844677006FA992 /* FIRAppTest.m */, DEE14D771E844677006FA992 /* FIRBundleUtilTest.m */, + ED34CF4A20DC16DC000EA5D1 /* FIRComponentContainerTest.m */, + ED34CF4D20DC16DD000EA5D1 /* FIRComponentTypeTest.m */, DEE14D781E844677006FA992 /* FIRConfigurationTest.m */, DEE14D791E844677006FA992 /* FIRLoggerTest.m */, + ED8C80FA2088EFA10093EB8A /* FIRMutableDictionaryTest.m */, + ED8C80FB2088EFA10093EB8A /* FIRNetworkTest.m */, DEE14D7A1E844677006FA992 /* FIROptionsTest.m */, + ED8C80FC2088EFA20093EB8A /* FIRReachabilityCheckerTest.m */, + DEE14D7B1E844677006FA992 /* FIRTestCase.h */, DEE14D7C1E844677006FA992 /* FIRTestCase.m */, + ED34CF4C20DC16DD000EA5D1 /* FIRTestComponents.h */, + ED34CF4B20DC16DC000EA5D1 /* FIRTestComponents.m */, DEE14D7D1E844677006FA992 /* Tests-Info.plist */, + ED8C80FD2088EFA20093EB8A /* third_party */, ); path = Tests; sourceTree = "<group>"; @@ -3621,12 +3638,15 @@ D064E6AF1ED9B31C001956DF /* FIRAppAssociationRegistrationUnitTests.m in Sources */, ED8C81012088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */, D064E6B01ED9B31C001956DF /* FIRAppTest.m in Sources */, + ED34CF5220DC16DD000EA5D1 /* FIRTestComponents.m in Sources */, D064E6B11ED9B31C001956DF /* FIRConfigurationTest.m in Sources */, + ED34CF5520DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */, DE4B26E120855F500030A38C /* FIRAppEnvironmentUtilTest.m in Sources */, D064E6B21ED9B31C001956DF /* FIRLoggerTest.m in Sources */, D064E6B31ED9B31C001956DF /* FIROptionsTest.m in Sources */, ED8C810A2088EFA20093EB8A /* GTMHTTPServer.m in Sources */, D064E6B41ED9B31C001956DF /* FIRBundleUtilTest.m in Sources */, + ED34CF4F20DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */, EDD43AA520BF7C7B005EBB36 /* FIRAnalyticsConfigurationTest.m in Sources */, D064E6B51ED9B31C001956DF /* FIRTestCase.m in Sources */, ); @@ -4080,12 +4100,15 @@ DEAAD3DA1FBA34250053BF48 /* FIROptionsTest.m in Sources */, ED8C81022088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */, DEAAD3D51FBA34250053BF48 /* FIRAppAssociationRegistrationUnitTests.m in Sources */, + ED34CF5320DC16DD000EA5D1 /* FIRTestComponents.m in Sources */, DEAAD3D91FBA34250053BF48 /* FIRLoggerTest.m in Sources */, + ED34CF5620DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */, DE4B26E220855F520030A38C /* FIRAppEnvironmentUtilTest.m in Sources */, DEAAD3D61FBA34250053BF48 /* FIRAppTest.m in Sources */, DEAAD3D81FBA34250053BF48 /* FIRConfigurationTest.m in Sources */, ED8C810B2088EFA20093EB8A /* GTMHTTPServer.m in Sources */, DEAAD3DB1FBA34250053BF48 /* FIRTestCase.m in Sources */, + ED34CF5020DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */, EDD43AA620BF7C7B005EBB36 /* FIRAnalyticsConfigurationTest.m in Sources */, DEAAD3D71FBA34250053BF48 /* FIRBundleUtilTest.m in Sources */, ); @@ -4164,12 +4187,15 @@ DEE14D8E1E84468D006FA992 /* FIRAppAssociationRegistrationUnitTests.m in Sources */, ED8C81002088EFA20093EB8A /* FIRMutableDictionaryTest.m in Sources */, DEE14D8F1E84468D006FA992 /* FIRAppTest.m in Sources */, + ED34CF5120DC16DD000EA5D1 /* FIRTestComponents.m in Sources */, DEE14D911E84468D006FA992 /* FIRConfigurationTest.m in Sources */, + ED34CF5420DC16DD000EA5D1 /* FIRComponentTypeTest.m in Sources */, DE4B26E020855F4C0030A38C /* FIRAppEnvironmentUtilTest.m in Sources */, DEE14D921E84468D006FA992 /* FIRLoggerTest.m in Sources */, DEE14D931E84468D006FA992 /* FIROptionsTest.m in Sources */, ED8C81092088EFA20093EB8A /* GTMHTTPServer.m in Sources */, DEE14D901E84468D006FA992 /* FIRBundleUtilTest.m in Sources */, + ED34CF4E20DC16DD000EA5D1 /* FIRComponentContainerTest.m in Sources */, EDD43AA420BF7C7B005EBB36 /* FIRAnalyticsConfigurationTest.m in Sources */, DEE14D941E84468D006FA992 /* FIRTestCase.m in Sources */, ); |