diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 8d6925ed2df..2a3e6fe8d07 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -55,8 +55,10 @@ jobs: cache_key: ${{ matrix.os }} - name: Initialize xcodebuild run: scripts/setup_spm_tests.sh - - name: iOS Unit Tests + - name: Objective-C Unit Tests run: scripts/third_party/travis/retry.sh ./scripts/build.sh StorageUnit iOS spm + - name: Swift Unit Tests + run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseStorageUnit iOS spm spm-cron: # Don't run on private repo. diff --git a/Example/watchOSSample/Podfile b/Example/watchOSSample/Podfile index cee4e1ca041..f6814898c3c 100644 --- a/Example/watchOSSample/Podfile +++ b/Example/watchOSSample/Podfile @@ -10,6 +10,7 @@ target 'SampleWatchAppWatchKitExtension' do pod 'FirebaseCore', :path => '../../' pod 'FirebaseCoreInternal', :path => '../../' pod 'FirebaseMessaging', :path => '../../' + pod 'FirebaseCoreExtension', :path => '../../' pod 'FirebaseCoreInternal', :path => '../../' pod 'FirebaseCoreDiagnostics', :path => '../../' pod 'FirebaseInstallations', :path => '../../' diff --git a/FirebaseAppCheck/Interop/FIRAppCheckInterop.h b/FirebaseAppCheck/Interop/FIRAppCheckInterop.h index d2b87e210f8..c08f729b6b4 100644 --- a/FirebaseAppCheck/Interop/FIRAppCheckInterop.h +++ b/FirebaseAppCheck/Interop/FIRAppCheckInterop.h @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(AppCheckTokenHandlerInterop) typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); -NS_SWIFT_NAME(AppCheckInterop) @protocol FIRAppCheckInterop +NS_SWIFT_NAME(AppCheckInterop) @protocol FIRAppCheckInterop /// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new /// token and updates the cache. diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 837a3f39a7b..85b2f8607f1 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -95,6 +95,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration 'FirebaseCore/Tests/SwiftUnit/**/*.swift', 'FirebaseCore/Tests/SwiftUnit/**/*.h', 'FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/*', + 'SharedTestUtilities/ExceptionCatcher.[mh]', 'SharedTestUtilities/FIROptionsMock.[mh]', ] swift_unit_tests.pod_target_xcconfig = { diff --git a/FirebaseCore/Tests/SwiftUnit/FirebaseCore-unit-Bridging-Header.h b/FirebaseCore/Tests/SwiftUnit/FirebaseCore-unit-Bridging-Header.h index c1c36c64066..93325036a02 100644 --- a/FirebaseCore/Tests/SwiftUnit/FirebaseCore-unit-Bridging-Header.h +++ b/FirebaseCore/Tests/SwiftUnit/FirebaseCore-unit-Bridging-Header.h @@ -13,5 +13,5 @@ // limitations under the License. #import "FirebaseCore/Extension/FirebaseCoreInternal.h" -#import "FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.h" +#import "SharedTestUtilities/ExceptionCatcher.h" #import "SharedTestUtilities/FIROptionsMock.h" diff --git a/FirebaseMessaging/Interop/FIRMessagingInterop.h b/FirebaseMessaging/Interop/FIRMessagingInterop.h index 5404443152e..ef5d52849ca 100644 --- a/FirebaseMessaging/Interop/FIRMessagingInterop.h +++ b/FirebaseMessaging/Interop/FIRMessagingInterop.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN /** Connector for bridging communication between Firebase SDKs and FIRMessaging API. */ -NS_SWIFT_NAME(MessagingInterop) @protocol FIRMessagingInterop +NS_SWIFT_NAME(MessagingInterop) @protocol FIRMessagingInterop /** * The FCM registration token is used to identify this device so that FCM can send notifications to diff --git a/FirebaseStorage/Tests/Unit/FIRStorageComponentTests.m b/FirebaseStorage/Tests/Unit/FIRStorageComponentTests.m deleted file mode 100644 index 54014b628f7..00000000000 --- a/FirebaseStorage/Tests/Unit/FIRStorageComponentTests.m +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 -#import - -#ifdef TODO -// Port the component tests to Swift - -#import "FirebaseCore/Internal/FirebaseCoreInternal.h" - -//#import "FirebaseStorage/Sources/FIRStorageComponent.h" -#import "SharedTestUtilities/FIRComponentTestUtilities.h" - -// Make FIRComponentRegistrant conformance visible to the tests and expose the initializer. -@interface FIRStorageComponent () -/// Internal initializer. -- (instancetype)initWithApp:(FIRApp *)app; -@end - -@interface FIRStorageComponentTests : XCTestCase -@end - -@implementation FIRStorageComponentTests - -#pragma mark - Interoperability Tests - -// Tests that the right number of components are being provided for the container. -- (void)testComponentsBeingRegistered { - // Check the count, because any time a new component is added it should be added to the test suite - // as well. - NSArray *components = [FIRStorageComponent componentsToRegister]; - XCTAssertTrue(components.count == 1); - - FIRComponent *component = [components firstObject]; - XCTAssert(component.protocol == @protocol(FIRStorageMultiBucketProvider)); -} - -/// Tests that a FIRIMPLStorage instance can be created properly by the FIRStorageComponent. -- (void)testStorageInstanceCreation { - // Get a mocked app, but don't use the default helper since it uses this class in the - // implementation. - id app = [self appMockWithOptions]; - FIRStorageComponent *component = [[FIRStorageComponent alloc] initWithApp:app]; - FIRIMPLStorage *storage = [component storageForBucket:@"someBucket"]; - XCTAssertNotNil(storage); -} - -/// Tests that the component container caches instances of FIRStorageComponent. -- (void)testMultipleComponentInstancesCreated { - // App isn't used in any of this, so a simple class mock works for simplicity. - id app = OCMClassMock([FIRApp class]); - NSMutableSet *registrants = [NSMutableSet setWithObject:[FIRStorageComponent class]]; - FIRComponentContainer *container = [[FIRComponentContainer alloc] initWithApp:app - registrants:registrants]; - id provider1 = - FIR_COMPONENT(FIRStorageMultiBucketProvider, container); - XCTAssertNotNil(provider1); - - id provider2 = - FIR_COMPONENT(FIRStorageMultiBucketProvider, container); - XCTAssertNotNil(provider2); - - // Ensure they're the same instance. - XCTAssertEqual(provider1, provider2); -} - -/// Tests that instances of FIRIMPLStorage created are different. -- (void)testMultipleStorageInstancesCreated { - // Get a mocked app, but don't use the default helper since is uses this class in the - // implementation. - id app = [self appMockWithOptions]; - NSMutableSet *registrants = [NSMutableSet setWithObject:[FIRStorageComponent class]]; - FIRComponentContainer *container = [[FIRComponentContainer alloc] initWithApp:app - registrants:registrants]; - id provider = - FIR_COMPONENT(FIRStorageMultiBucketProvider, container); - XCTAssertNotNil(provider); - - FIRIMPLStorage *storage1 = [provider storageForBucket:@"randomBucket"]; - XCTAssertNotNil(storage1); - FIRIMPLStorage *storage2 = [provider storageForBucket:@"randomBucket"]; - XCTAssertNotNil(storage2); - - // Ensure that they're the same instance - XCTAssertEqual(storage1, storage2); - XCTAssertEqualObjects(storage1, storage2); - - // Create another bucket with a different provider from above. - FIRIMPLStorage *storage3 = [provider storageForBucket:@"differentBucket"]; - XCTAssertNotNil(storage3); - - // Ensure it's a different object. - XCTAssertNotEqualObjects(storage2, storage3); -} - -#pragma mark - Test Helpers - -/// Creates a FIRApp mock with a googleAppID. -- (id)appMockWithOptions { - id app = OCMClassMock([FIRApp class]); - OCMStub([app name]).andReturn(@"__FIRAPP_DEFAULT"); - id options = OCMClassMock([FIROptions class]); - OCMStub([options googleAppID]).andReturn(@"dummyAppID"); - OCMStub([(FIRApp *)app options]).andReturn(options); - return app; -} - -@end -#endif diff --git a/FirebaseStorage/Tests/Unit/FIRStorageTests.m b/FirebaseStorage/Tests/Unit/FIRStorageTests.m index 5b3e3b2fe9e..757846002f9 100644 --- a/FirebaseStorage/Tests/Unit/FIRStorageTests.m +++ b/FirebaseStorage/Tests/Unit/FIRStorageTests.m @@ -16,10 +16,6 @@ #import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" -#ifdef TODO -// Port the component tests to Swift - -//#import "FirebaseStorage/Sources/FIRStorageComponent.h" #import "FirebaseStorage/Sources/FIRStorageReference_Private.h" #import "FirebaseStorage/Sources/FIRStorage_Private.h" #import "SharedTestUtilities/FIRComponentTestUtilities.h" @@ -48,140 +44,15 @@ - (void)tearDown { [super tearDown]; } -- (void)testBucketNotEnforced { - FIROptions *mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(@""); - FIRApp *app = [FIRStorageTestHelpers mockedApp]; - OCMStub([app name]).andReturn(kFIRStorageAppName); - OCMStub([(FIRApp *)app options]).andReturn(mockOptions); - - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:app]; - [storage referenceForURL:@"gs://benwu-test1.storage.firebase.com/child"]; - [storage referenceForURL:@"gs://benwu-test2.storage.firebase.com/child"]; -} - -- (void)testBucketEnforced { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app - URL:@"gs://benwu-test1.storage.firebase.com"]; - [storage referenceForURL:@"gs://benwu-test1.storage.firebase.com/child"]; - storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://benwu-test1.storage.firebase.com/"]; - [storage referenceForURL:@"gs://benwu-test1.storage.firebase.com/child"]; - XCTAssertThrows([storage referenceForURL:@"gs://benwu-test2.storage.firebase.com/child"]); -} - -- (void)testInitWithCustomUrl { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; - XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[storage reference] description]); - storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com/"]; - XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[storage reference] description]); -} - -- (void)testInitWithWrongScheme { - XCTAssertThrows([FIRIMPLStorage storageForApp:self.app URL:@"http://foo-bar.appspot.com"]); -} - -- (void)testInitWithNoScheme { - XCTAssertThrows([FIRIMPLStorage storageForApp:self.app URL:@"foo-bar.appspot.com"]); -} - -- (void)testInitWithNilURL { - XCTAssertThrows([FIRIMPLStorage storageForApp:self.app URL:(id _Nonnull)nil]); -} - -- (void)testInitWithPath { - XCTAssertThrows([FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com/child"]); -} - -- (void)testInitWithDefaultAndCustomUrl { - FIRIMPLStorage *customInstance = [FIRIMPLStorage storageForApp:self.app - URL:@"gs://foo-bar.appspot.com"]; - FIRIMPLStorage *defaultInstance = [FIRIMPLStorage storageForApp:self.app]; - XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[customInstance reference] description]); - XCTAssertEqualObjects(@"gs://bucket/", [[defaultInstance reference] description]); -} - -- (void)testStorageDefaultApp { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app]; - XCTAssertEqualObjects(storage.app.name, ((FIRApp *)self.app).name); - [storage reference]; // Initialize Storage - XCTAssertNotNil(storage.fetcherServiceForApp); -} - -- (void)testStorageCustomApp { - id mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); - id secondApp = [FIRStorageTestHelpers mockedApp]; - OCMStub([secondApp name]).andReturn(@"secondApp"); - OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:secondApp]; - [storage reference]; // Initialize Storage - XCTAssertNotEqual(storage.app.name, ((FIRApp *)self.app).name); - XCTAssertNotNil(storage.fetcherServiceForApp); - XCTAssertNotEqualObjects(storage.fetcherServiceForApp, - [FIRIMPLStorage storageForApp:self.app].fetcherServiceForApp); -} - -- (void)testStorageNoBucketInConfig { - id mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(nil); - id secondApp = [FIRStorageTestHelpers mockedApp]; - OCMStub([secondApp name]).andReturn(@"secondApp"); - OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); - XCTAssertThrows([FIRIMPLStorage storageForApp:secondApp]); -} - -- (void)testStorageEmptyBucketInConfig { - id mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(@""); - id secondApp = [FIRStorageTestHelpers mockedApp]; - OCMStub([secondApp name]).andReturn(@"secondApp"); - OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:secondApp]; - FIRIMPLStorageReference *storageRef = [storage referenceForURL:@"gs://bucket/path/to/object"]; - XCTAssertEqualObjects(storageRef.bucket, @"bucket"); -} - -- (void)testStorageWrongBucketInConfig { - id mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(@"notMyBucket"); - id secondApp = [FIRStorageTestHelpers mockedApp]; - OCMStub([secondApp name]).andReturn(@"secondApp"); - OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:secondApp]; - XCTAssertEqualObjects([(FIRApp *)secondApp options].storageBucket, @"notMyBucket"); - XCTAssertThrows([storage referenceForURL:@"gs://bucket/path/to/object"]); -} - -- (void)testUseEmulator { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; - [storage useEmulatorWithHost:@"localhost" port:8080]; - XCTAssertNoThrow([storage reference]); -} - -- (void)testUseEmulatorValidatesHost { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; - XCTAssertThrows([storage useEmulatorWithHost:@"" port:8080]); -} - -- (void)testUseEmulatorValidatesPort { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; - XCTAssertThrows([storage useEmulatorWithHost:@"localhost" port:-1]); -} - -- (void)testUseEmulatorCannotBeCalledAfterObtainingReference { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app - URL:@"gs://benwu-test1.storage.firebase.com"]; - [storage reference]; - XCTAssertThrows([storage useEmulatorWithHost:@"localhost" port:8080]); -} - - (void)testRefDefaultApp { - FIRIMPLStorageReference *convenienceRef = - [[FIRIMPLStorage storageForApp:self.app] referenceForURL:@"gs://bucket/path/to/object"]; + FIRIMPLStorage *storage = [[FIRIMPLStorage alloc] initWithApp:self.app + bucket:@"bucket" + auth:nil + appCheck:nil]; + FIRIMPLStorageReference *convenienceRef = [storage referenceForURL:@"gs://bucket/path/to/object"]; FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; - FIRIMPLStorageReference *builtRef = - [[FIRIMPLStorageReference alloc] initWithStorage:[FIRIMPLStorage storageForApp:self.app] - path:path]; + FIRIMPLStorageReference *builtRef = [[FIRIMPLStorageReference alloc] initWithStorage:storage + path:path]; XCTAssertEqualObjects([convenienceRef description], [builtRef description]); XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); } @@ -192,60 +63,43 @@ - (void)testRefCustomApp { id secondApp = [FIRStorageTestHelpers mockedApp]; OCMStub([secondApp name]).andReturn(@"secondApp"); OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRIMPLStorage *storage2 = [[FIRIMPLStorage alloc] initWithApp:secondApp + bucket:@"bucket" + auth:nil + appCheck:nil]; FIRIMPLStorageReference *convenienceRef = - [[FIRIMPLStorage storageForApp:secondApp] referenceForURL:@"gs://bucket/path/to/object"]; + [storage2 referenceForURL:@"gs://bucket/path/to/object"]; FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; - FIRIMPLStorageReference *builtRef = - [[FIRIMPLStorageReference alloc] initWithStorage:[FIRIMPLStorage storageForApp:secondApp] - path:path]; + FIRIMPLStorageReference *builtRef = [[FIRIMPLStorageReference alloc] initWithStorage:storage2 + path:path]; XCTAssertEqualObjects([convenienceRef description], [builtRef description]); XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); } - (void)testRootRefDefaultApp { - FIRIMPLStorageReference *convenienceRef = [[FIRIMPLStorage storageForApp:self.app] reference]; + FIRIMPLStorage *storage = [[FIRIMPLStorage alloc] initWithApp:self.app + bucket:@"bucket" + auth:nil + appCheck:nil]; + FIRIMPLStorageReference *convenienceRef = [storage reference]; FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; - FIRIMPLStorageReference *builtRef = - [[FIRIMPLStorageReference alloc] initWithStorage:[FIRIMPLStorage storageForApp:self.app] - path:path]; + FIRIMPLStorageReference *builtRef = [[FIRIMPLStorageReference alloc] initWithStorage:storage + path:path]; XCTAssertEqualObjects([convenienceRef description], [builtRef description]); XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); } - (void)testRefWithPathDefaultApp { - FIRIMPLStorageReference *convenienceRef = - [[FIRIMPLStorage storageForApp:self.app] referenceWithPath:@"path/to/object"]; + FIRIMPLStorage *storage = [[FIRIMPLStorage alloc] initWithApp:self.app + bucket:@"bucket" + auth:nil + appCheck:nil]; + FIRIMPLStorageReference *convenienceRef = [storage referenceForURL:@"gs://bucket/path/to/object"]; FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; - FIRIMPLStorageReference *builtRef = - [[FIRIMPLStorageReference alloc] initWithStorage:[FIRIMPLStorage storageForApp:self.app] - path:path]; + FIRIMPLStorageReference *builtRef = [[FIRIMPLStorageReference alloc] initWithStorage:storage + path:path]; XCTAssertEqualObjects([convenienceRef description], [builtRef description]); XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); } -- (void)testEqual { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app]; - FIRIMPLStorage *copy = [storage copy]; - XCTAssertEqualObjects(storage.app.name, copy.app.name); -} - -- (void)testNotEqual { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app]; - id mockOptions = OCMClassMock([FIROptions class]); - OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); - id secondApp = [FIRStorageTestHelpers mockedApp]; - OCMStub([secondApp name]).andReturn(@"secondApp"); - OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); - FIRIMPLStorage *secondStorage = [FIRIMPLStorage storageForApp:secondApp]; - XCTAssertNotEqualObjects(storage, secondStorage); -} - -- (void)testHash { - FIRIMPLStorage *storage = [FIRIMPLStorage storageForApp:self.app]; - FIRIMPLStorage *copy = [storage copy]; - XCTAssertEqual([storage hash], [copy hash]); -} - @end - -#endif diff --git a/FirebaseStorageSwift/Sources/Storage.swift b/FirebaseStorageSwift/Sources/Storage.swift index 8f8d5b27eb6..6e617955331 100644 --- a/FirebaseStorageSwift/Sources/Storage.swift +++ b/FirebaseStorageSwift/Sources/Storage.swift @@ -176,6 +176,10 @@ import FirebaseAuthInterop // MARK: - NSObject overrides + @objc override open func copy() -> Any { + return Storage(copy: self) + } + @objc override open func isEqual(_ object: Any?) -> Bool { guard let ref = object as? Storage else { return false @@ -203,4 +207,9 @@ import FirebaseAuthInterop impl = FIRIMPLStorage(app: app, bucket: bucket, auth: auth, appCheck: appCheck) self.app = impl.app } + + internal init(copy: Storage) { + impl = copy.impl.copy() as! FIRIMPLStorage + app = impl.app + } } diff --git a/FirebaseStorageSwift/Tests/Unit/StorageComponentTests.swift b/FirebaseStorageSwift/Tests/Unit/StorageComponentTests.swift new file mode 100644 index 00000000000..50b29052ed3 --- /dev/null +++ b/FirebaseStorageSwift/Tests/Unit/StorageComponentTests.swift @@ -0,0 +1,95 @@ +// Copyright 2022 Google LLC +// +// 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 + +import FirebaseCore +@testable import FirebaseStorage + +import FirebaseAppCheckInterop +import FirebaseAuthInterop +import SharedTestUtilities + +import XCTest + +class StorageComponentTests: XCTestCase { + static var app: FirebaseApp! + + override class func setUp() { + let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", + gcmSenderID: "00000000000000000-00000000000-000000000") + options.projectID = "myProjectID" + app = FirebaseApp(instanceWithName: "test", options: options) + } + + // MARK: Interoperability Tests + + /// Tests that the right number of components are being provided for the container. + func testComponentsBeingRegistered() throws { + let components = StorageComponent.componentsToRegister() + XCTAssert(components.count == 1) + } + + /// Tests that a Storage instance can be created properly by the StorageComponent. + func testStorageInstanceCreation() throws { + let component = StorageComponent(app: StorageComponentTests.app) + let storage = component.storage(for: "someBucket") + XCTAssertNotNil(storage) + } + + /// Tests that the component container caches instances of StorageComponent. + func testMultipleComponentInstancesCreated() throws { + let registrants = NSMutableSet(array: [StorageComponent.self]) + let container = FirebaseComponentContainer( + app: StorageComponentTests.app, + registrants: registrants + ) + + let provider1 = ComponentType.instance(for: StorageProvider.self, + in: container) + XCTAssertNotNil(provider1) + + let provider2 = ComponentType.instance(for: StorageProvider.self, + in: container) + XCTAssertNotNil(provider2) + + // Ensure they're the same instance. + XCTAssert(provider1 === provider2) + } + + /// Tests that instances of Storage created are different. + func testMultipleStorageInstancesCreated() throws { + let registrants = NSMutableSet(array: [StorageComponent.self]) + let container = FirebaseComponentContainer( + app: StorageComponentTests.app, + registrants: registrants + ) + + let provider = ComponentType.instance(for: StorageProvider.self, + in: container) + XCTAssertNotNil(provider) + + let storage1 = provider.storage(for: "randomBucket") + let storage2 = provider.storage(for: "randomBucket") + XCTAssertNotNil(storage1) + + // Ensure they're the same instance. + XCTAssert(storage1 === storage2) + + let storage3 = provider.storage(for: "differentBucket") + XCTAssertNotNil(storage3) + + XCTAssert(storage1 !== storage3) + } +} diff --git a/FirebaseStorageSwift/Tests/Unit/StorageTests.swift b/FirebaseStorageSwift/Tests/Unit/StorageTests.swift new file mode 100644 index 00000000000..7eddeb08913 --- /dev/null +++ b/FirebaseStorageSwift/Tests/Unit/StorageTests.swift @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC +// +// 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 + +import FirebaseCore +@testable import FirebaseStorage + +import FirebaseAppCheckInterop +import FirebaseAuthInterop +import SharedTestUtilities + +import XCTest + +class StorageTests: XCTestCase { + static var app: FirebaseApp? + override class func setUp() { + let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", + gcmSenderID: "00000000000000000-00000000000-000000000") + options.projectID = "myProjectID" + FirebaseApp.configure(name: "test", options: options) + app = FirebaseApp.app(name: "test") + } + + func testBucketNotEnforced() throws { + let app = try getApp(bucket: "") + let storage = Storage.storage(app: app) + _ = storage.reference(forURL: "gs://benwu-test1.storage.firebase.com/child") + _ = storage.reference(forURL: "gs://benwu-test2.storage.firebase.com/child") + } + + func testBucketEnforced() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app, url: "gs://benwu-test1.storage.firebase.com") + _ = storage.reference(forURL: "gs://benwu-test1.storage.firebase.com/child") + XCTAssertThrowsObjCException { + _ = storage.reference(forURL: "gs://benwu-test2.storage.firebase.com/child") + } + } + + func testInitWithCustomURL() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com") + XCTAssertEqual("gs://foo-bar.appspot.com/", storage.reference().description) + let storage2 = Storage.storage(app: app, url: "gs://foo-bar.appspot.com/") + XCTAssertEqual("gs://foo-bar.appspot.com/", storage2.reference().description) + } + + func testInitWithWrongScheme() throws { + let app = try getApp(bucket: "bucket") + XCTAssertThrowsObjCException { + _ = Storage.storage(app: app, url: "http://foo-bar.appspot.com") + } + } + + func testInitWithNoScheme() throws { + let app = try getApp(bucket: "bucket") + XCTAssertThrowsObjCException { + _ = Storage.storage(app: app, url: "foo-bar.appspot.com") + } + } + + func testInitWithoutURL() throws { + let app = try getApp(bucket: "bucket") + XCTAssertNoThrowObjCException { + _ = Storage.storage(app: app) + } + } + + func testInitWithPath() throws { + let app = try getApp(bucket: "bucket") + XCTAssertThrowsObjCException { + _ = Storage.storage(app: app, url: "gs://foo-bar.appspot.com/child") + } + } + + func testInitWithDefaultAndCustomURL() throws { + let app = try getApp(bucket: "bucket") + let defaultInstance = Storage.storage(app: app) + let customInstance = Storage.storage(app: app, url: "gs://foo-bar.appspot.com") + XCTAssertEqual("gs://foo-bar.appspot.com/", customInstance.reference().description) + XCTAssertEqual("gs://bucket/", defaultInstance.reference().description) + } + + func testStorageDefaultApp() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app) + XCTAssertEqual(storage.app.name, app.name) + } + + func testStorageNoBucketInConfig() throws { + let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", + gcmSenderID: "00000000000000000-00000000000-000000000") + options.projectID = "myProjectID" + let name = "StorageTestsNil" + let app = FirebaseApp(instanceWithName: name, options: options) + XCTAssertThrowsObjCException { + _ = Storage.storage(app: app) + } + } + + func testStorageEmptyBucketInConfig() throws { + let app = try getApp(bucket: "") + let storage = Storage.storage(app: app) + let ref = storage.reference(forURL: "gs://bucket/path/to/object") + XCTAssertEqual(ref.bucket, "bucket") + } + + func testStorageWrongBucketInConfig() throws { + let app = try getApp(bucket: "notMyBucket") + let storage = Storage.storage(app: app) + XCTAssertThrowsObjCException { + _ = storage.reference(forURL: "gs://bucket/path/to/object") + } + } + + func testUseEmulator() throws { + let app = try getApp(bucket: "bucket-for-testUseEmulator") + let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com") + storage.useEmulator(withHost: "localhost", port: 8080) + XCTAssertNoThrow(storage.reference()) + } + + func testUseEmulatorValidatesHost() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com") + XCTAssertThrowsObjCException { + storage.useEmulator(withHost: "", port: 8080) + } + } + + func testUseEmulatorValidatesPort() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com") + XCTAssertThrowsObjCException { + storage.useEmulator(withHost: "localhost", port: -1) + } + } + + func testUseEmulatorCannotBeCalledAfterObtainingReference() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app, url: "gs://benwu-test1.storage.firebase.com") + _ = storage.reference() + XCTAssertThrowsObjCException { + storage.useEmulator(withHost: "localhost", port: 8080) + } + } + + func testEqual() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app) + let copy = try XCTUnwrap(storage.copy() as? Storage) + XCTAssertEqual(storage.app.name, copy.app.name) + XCTAssertEqual(storage.hash, copy.hash) + } + + func testNotEqual() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app) + let secondApp = try getApp(bucket: "bucket2") + let storage2 = Storage.storage(app: secondApp) + XCTAssertNotEqual(storage, storage2) + XCTAssertNotEqual(storage.hash, storage2.hash) + } + + func testHash() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app) + let copy = try XCTUnwrap(storage.copy() as? Storage) + XCTAssertEqual(storage.app.name, copy.app.name) + } + + // MARK: Private Helpers + + // Cache the app associated with each Storage bucket + private static var appDictionary: [String: FirebaseApp] = [:] + + private func getApp(bucket: String) throws -> FirebaseApp { + let savedApp = StorageTests.appDictionary[bucket] + guard savedApp == nil else { + return try XCTUnwrap(savedApp) + } + let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", + gcmSenderID: "00000000000000000-00000000000-000000000") + options.projectID = "myProjectID" + options.storageBucket = bucket + let name = "StorageTests\(bucket)" + let app = FirebaseApp(instanceWithName: name, options: options) + StorageTests.appDictionary[bucket] = app + return app + } + + private func XCTAssertThrowsObjCException(_ closure: @escaping () -> Void) { + XCTAssertThrowsError(try ExceptionCatcher.catchException(closure)) + } + + private func XCTAssertNoThrowObjCException(_ closure: @escaping () -> Void) { + XCTAssertNoThrow(try ExceptionCatcher.catchException(closure)) + } +} diff --git a/Package.swift b/Package.swift index d1b98ff6101..7d7a01cefb3 100644 --- a/Package.swift +++ b/Package.swift @@ -737,6 +737,9 @@ let package = Package( .testTarget( name: "FirebaseFunctionsUnit", dependencies: ["FirebaseFunctions", + "FirebaseAppCheckInterop", + "FirebaseAuthInterop", + "FirebaseMessagingInterop", "SharedTestUtilities"], path: "FirebaseFunctions/Tests/Unit", cSettings: [ @@ -959,7 +962,11 @@ let package = Package( .target( name: "SharedTestUtilities", - dependencies: ["FirebaseCore", "OCMock"], + dependencies: ["FirebaseCore", + "FirebaseAppCheckInterop", + "FirebaseAuthInterop", + "FirebaseMessagingInterop", + "OCMock"], path: "SharedTestUtilities", publicHeadersPath: "./", cSettings: [ @@ -1073,6 +1080,15 @@ let package = Package( ], path: "FirebaseStorageSwift/Sources" ), + .testTarget( + name: "FirebaseStorageUnit", + dependencies: ["FirebaseStorage", + "SharedTestUtilities"], + path: "FirebaseStorageSwift/Tests/Unit", + cSettings: [ + .headerSearchPath("../../../"), + ] + ), .testTarget( name: "StorageObjcIntegration", dependencies: ["FirebaseStorage"], diff --git a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.h b/SharedTestUtilities/ExceptionCatcher.h similarity index 100% rename from FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.h rename to SharedTestUtilities/ExceptionCatcher.h diff --git a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.m b/SharedTestUtilities/ExceptionCatcher.m similarity index 95% rename from FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.m rename to SharedTestUtilities/ExceptionCatcher.m index a18ff443460..2113a28a578 100644 --- a/FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.m +++ b/SharedTestUtilities/ExceptionCatcher.m @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "FirebaseCore/Tests/SwiftUnit/SwiftTestingUtilities/ExceptionCatcher.h" +#import "SharedTestUtilities/ExceptionCatcher.h" @implementation ExceptionCatcher diff --git a/scripts/spm_test_schemes/FirebaseStorageUnit.xcscheme b/scripts/spm_test_schemes/FirebaseStorageUnit.xcscheme new file mode 100644 index 00000000000..62f711b1da8 --- /dev/null +++ b/scripts/spm_test_schemes/FirebaseStorageUnit.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/spm_test_schemes/StorageUnit.xcscheme b/scripts/spm_test_schemes/StorageUnit.xcscheme index 3992cc59f9d..be41af35732 100644 --- a/scripts/spm_test_schemes/StorageUnit.xcscheme +++ b/scripts/spm_test_schemes/StorageUnit.xcscheme @@ -1,6 +1,6 @@ + buildForAnalyzing = "NO">