diff options
Diffstat (limited to 'Example/Core')
-rw-r--r-- | Example/Core/Tests/FIRComponentContainerTest.m | 157 | ||||
-rw-r--r-- | Example/Core/Tests/FIRComponentTypeTest.m | 60 | ||||
-rw-r--r-- | Example/Core/Tests/FIRTestComponents.h | 63 | ||||
-rw-r--r-- | Example/Core/Tests/FIRTestComponents.m | 118 |
4 files changed, 398 insertions, 0 deletions
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/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 |