mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
* [skip ci] [will revert] Add debug printing to `pod_lib_lint.rb`
* Reorganize FirebaseCore libraries for SPM and CP
* [skip ci] Revert "[skip ci] [will revert] Add debug printing to `pod_lib_lint.rb`"
This reverts commit 2a837e39708c21b0a324743ab226bd6c01047de7.
* Review and fix CI
* Remove `heartbeat_logging.yml` and add `core_internal.yml`
* Remove trailing whitespace
* Fix more whitespace 😞
* Fix `core_internal.yml` scheme name
* Update `check_imports.swift` and TODO
* Review
* Add FirebaseCoreInternal pod to Firestore example's Podfile
* [skip ci] Review - remove TODOs
* [skip ci] Remove duplicate `XCTest` import
249 lines
9.9 KiB
Objective-C
249 lines
9.9 KiB
Objective-C
// 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 "FirebaseCore/Tests/Unit/FIRTestCase.h"
|
|
|
|
#import "FirebaseCore/Extension/FIRComponentType.h"
|
|
#import "FirebaseCore/Extension/FirebaseCoreInternal.h"
|
|
#import "FirebaseCore/Sources/FIRComponentContainerInternal.h"
|
|
#import "FirebaseCore/Tests/Unit/FIRTestComponents.h"
|
|
#import "SharedTestUtilities/FIROptionsMock.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<FIRLibrary>)klass
|
|
inSet:(NSMutableSet<Class> *)allRegistrants;
|
|
- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet<Class> *)allRegistrants;
|
|
@end
|
|
|
|
@interface FIRComponentContainer (TestInternalImplementations)
|
|
- (instancetype)initWithApp:(FIRApp *)app
|
|
components:(NSDictionary<NSString *, FIRComponentCreationBlock> *)components;
|
|
@end
|
|
|
|
@implementation FIRComponentContainer (TestInternalImplementations)
|
|
|
|
- (instancetype)initWithApp:(FIRApp *)app
|
|
components:(NSDictionary<NSString *, FIRComponentCreationBlock> *)components {
|
|
self = [self initWithApp:app registrants:[[NSMutableSet alloc] init]];
|
|
if (self) {
|
|
self.components = [components mutableCopy];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
@interface FIRComponentContainerTest : FIRTestCase {
|
|
FIRApp *_hostApp;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation FIRComponentContainerTest
|
|
|
|
- (void)tearDown {
|
|
_hostApp = nil;
|
|
[super tearDown];
|
|
}
|
|
|
|
#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)testComponentsPopulatedOnInit {
|
|
FIRComponentContainer *container = [self containerWithRegistrants:@[ [FIRTestClass class] ]];
|
|
|
|
// Verify that the block is stored.
|
|
NSString *protocolName = NSStringFromProtocol(@protocol(FIRTestProtocol));
|
|
FIRComponentCreationBlock creationBlock = container.components[protocolName];
|
|
XCTAssertNotNil(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],
|
|
[FIRTestClassCachedWithDep 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);
|
|
}
|
|
|
|
- (void)testRemoveAllComponents {
|
|
FIRComponentContainer *container = [self containerWithRegistrants:@[
|
|
[FIRTestClass class], [FIRTestClassCached class], [FIRTestClassEagerCached class],
|
|
[FIRTestClassCachedWithDep class]
|
|
]];
|
|
|
|
// Retrieve an instance of FIRTestClassCached to ensure it's cached.
|
|
id<FIRTestProtocolCached> cachedInstance1 = FIR_COMPONENT(FIRTestProtocolCached, container);
|
|
XCTAssertNotNil(cachedInstance1);
|
|
id<FIRTestProtocolEagerCached> eagerInstance1 =
|
|
FIR_COMPONENT(FIRTestProtocolEagerCached, container);
|
|
XCTAssertNotNil(eagerInstance1);
|
|
|
|
// FIRTestClassEagerCached and FIRTestClassCached instances should be cached at this point.
|
|
XCTAssertTrue(container.cachedInstances.count == 2);
|
|
|
|
// Remove all components.
|
|
[container removeAllComponents];
|
|
|
|
// Remove the instances.
|
|
[container removeAllCachedInstances];
|
|
|
|
// Verify that no new instances are created.
|
|
id<FIRTestProtocolCached> cachedInstance2 = FIR_COMPONENT(FIRTestProtocolCached, container);
|
|
XCTAssertNil(cachedInstance2);
|
|
id<FIRTestProtocolEagerCached> eagerInstance2 =
|
|
FIR_COMPONENT(FIRTestProtocolEagerCached, container);
|
|
XCTAssertNil(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 - Dependency Tests
|
|
|
|
- (void)testDependencyDoesntBlock {
|
|
/// Test a class that has a dependency, and fetching doesn't block the internal queue.
|
|
FIRComponentContainer *container = [self
|
|
containerWithRegistrants:@[ [FIRTestClassCached class], [FIRTestClassCachedWithDep class] ]];
|
|
XCTAssert(container.components.count == 2);
|
|
|
|
id<FIRTestProtocolCachedWithDep> instanceWithDep =
|
|
FIR_COMPONENT(FIRTestProtocolCachedWithDep, container);
|
|
XCTAssertNotNil(instanceWithDep);
|
|
}
|
|
|
|
- (void)testDependencyRemoveAllCachedInstancesDoesntBlock {
|
|
/// Test a class that has a dependency, and fetching doesn't block the internal queue.
|
|
FIRComponentContainer *container = [self
|
|
containerWithRegistrants:@[ [FIRTestClassCached class], [FIRTestClassCachedWithDep class] ]];
|
|
XCTAssert(container.components.count == 2);
|
|
|
|
id<FIRTestProtocolCachedWithDep> instanceWithDep =
|
|
FIR_COMPONENT(FIRTestProtocolCachedWithDep, container);
|
|
XCTAssertNotNil(instanceWithDep);
|
|
XCTAssertNotNil(instanceWithDep.testProperty);
|
|
|
|
// Both `instanceWithDep` and `testProperty` should be cached now.
|
|
XCTAssertTrue(container.cachedInstances.count == 2);
|
|
|
|
// Remove the instances and verify cachedInstances is empty, and doesn't block the queue.
|
|
[container removeAllCachedInstances];
|
|
XCTAssertTrue(container.cachedInstances.count == 0);
|
|
}
|
|
|
|
#pragma mark - Convenience Methods
|
|
|
|
/// Create a container that has registered the test class.
|
|
- (FIRComponentContainer *)containerWithRegistrants:(NSArray<Class> *)registrants {
|
|
FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID
|
|
GCMSenderID:kGCMSenderID];
|
|
_hostApp = [[FIRApp alloc] initInstanceWithName:@"fake_app" options:options];
|
|
NSMutableSet<Class> *allRegistrants = [NSMutableSet<Class> set];
|
|
|
|
// Initialize the container with the test classes.
|
|
for (Class c in registrants) {
|
|
[FIRComponentContainer registerAsComponentRegistrant:c inSet:allRegistrants];
|
|
}
|
|
|
|
// Override the app's container with the newly instantiated container.
|
|
FIRComponentContainer *container = [[FIRComponentContainer alloc] initWithApp:_hostApp
|
|
registrants:allRegistrants];
|
|
_hostApp.container = container;
|
|
|
|
// Instantiate all the components that were eagerly registered now that all other properties are
|
|
// configured.
|
|
[container instantiateEagerComponents];
|
|
|
|
return container;
|
|
}
|
|
|
|
@end
|