diff options
Diffstat (limited to 'Example/Storage/Tests/Unit')
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageDeleteTests.m | 164 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m | 188 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageMetadataTests.m | 282 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStoragePathTests.m | 234 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageReferenceTests.m | 163 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageTestHelpers.h | 127 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageTestHelpers.m | 128 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageTests.m | 214 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageTokenAuthorizerTests.m | 226 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m | 199 | ||||
-rw-r--r-- | Example/Storage/Tests/Unit/FIRStorageUtilsTests.m | 125 |
11 files changed, 2050 insertions, 0 deletions
diff --git a/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m b/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m new file mode 100644 index 0000000..42a3b1a --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m @@ -0,0 +1,164 @@ +// Copyright 2017 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 "FIRStorageDeleteTask.h" +#import "FIRStorageTestHelpers.h" + +@interface FIRStorageDeleteTests : XCTestCase + +@property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(strong, nonatomic) FIRStorageMetadata *metadata; +@property(strong, nonatomic) FIRStorage *storage; +@property(strong, nonatomic) id mockApp; + +@end + +@implementation FIRStorageDeleteTests + +- (void)setUp { + [super setUp]; + + NSDictionary *metadataDict = @{ @"bucket" : @"bucket", @"name" : @"path/to/object" }; + self.metadata = [[FIRStorageMetadata alloc] initWithDictionary:metadataDict]; + + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket.appspot.com"); + + self.mockApp = OCMClassMock([FIRApp class]); + OCMStub([self.mockApp name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)self.mockApp options]).andReturn(mockOptions); + + self.fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcherService.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:self.mockApp + fetcherService:self.fetcherService]; + + self.storage = [FIRStorage storageForApp:self.mockApp]; +} + +- (void)tearDown { + self.fetcherService = nil; + self.storage = nil; + self.mockApp = nil; + [super tearDown]; +} + +- (void)testFetcherConfiguration { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = + ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertEqualObjects(fetcher.request.URL, [FIRStorageTestHelpers objectURL]); +#pragma clang diagnostic pop + XCTAssertEqualObjects(fetcher.request.HTTPMethod, @"DELETE"); + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref + fetcherService:self.fetcherService + completion:^(NSError *error) { + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testSuccessfulFetch { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers successBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref + fetcherService:self.fetcherService + completion:^(NSError *error) { + XCTAssertEqual(error, nil); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthenticated { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthenticated"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthenticatedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageDeleteTask *task = + [[FIRStorageDeleteTask alloc] initWithReference:ref + fetcherService:self.fetcherService + completion:^(NSError *error) { + XCTAssertEqual(error.code, + FIRStorageErrorCodeUnauthenticated); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthorized { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthorized"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthorizedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageDeleteTask *task = + [[FIRStorageDeleteTask alloc] initWithReference:ref + fetcherService:self.fetcherService + completion:^(NSError *error) { + XCTAssertEqual(error.code, + FIRStorageErrorCodeUnauthorized); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchObjectDoesntExist { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchObjectDoesntExist"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers notFoundBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers notFoundPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageDeleteTask *task = + [[FIRStorageDeleteTask alloc] initWithReference:ref + fetcherService:self.fetcherService + completion:^(NSError *error) { + XCTAssertEqual(error.code, + FIRStorageErrorCodeObjectNotFound); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m new file mode 100644 index 0000000..72a057d --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m @@ -0,0 +1,188 @@ +// Copyright 2017 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 "FIRStorageGetMetadataTask.h" +#import "FIRStorageTestHelpers.h" + +@interface FIRStorageGetMetadataTests : XCTestCase + +@property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(strong, nonatomic) FIRStorageMetadata *metadata; +@property(strong, nonatomic) FIRStorage *storage; +@property(strong, nonatomic) id mockApp; + +@end + +@implementation FIRStorageGetMetadataTests + +- (void)setUp { + [super setUp]; + + NSDictionary *metadataDict = @{ @"bucket" : @"bucket", @"name" : @"path/to/object" }; + self.metadata = [[FIRStorageMetadata alloc] initWithDictionary:metadataDict]; + + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket.appspot.com"); + + self.mockApp = OCMClassMock([FIRApp class]); + OCMStub([self.mockApp name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)self.mockApp options]).andReturn(mockOptions); + + self.fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcherService.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:self.mockApp + fetcherService:self.fetcherService]; + + self.storage = [FIRStorage storageForApp:self.mockApp]; +} + +- (void)tearDown { + self.fetcherService = nil; + self.storage = nil; + self.mockApp = nil; + [super tearDown]; +} + +- (void)testFetcherConfiguration { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = + ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertEqualObjects(fetcher.request.URL, [FIRStorageTestHelpers objectURL]); +#pragma clang diagnostic pop + XCTAssertEqualObjects(fetcher.request.HTTPMethod, @"GET"); + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testSuccessfulFetch { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers successBlockWithMetadata:self.metadata]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertEqualObjects(self.metadata.bucket, metadata.bucket); + XCTAssertEqualObjects(self.metadata.name, metadata.name); + XCTAssertEqual(error, nil); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthenticated { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthenticated"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthenticatedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertEqual(metadata, nil); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthenticated); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthorized { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthorized"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthorizedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertEqual(metadata, nil); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthorized); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchObjectDoesntExist { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchObjectDoesntExist"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers notFoundBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers notFoundPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertEqual(metadata, nil); + XCTAssertEqual(error.code, FIRStorageErrorCodeObjectNotFound); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchBadJSON { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchBadJSON"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers invalidJSONBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertEqual(metadata, nil); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnknown); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m new file mode 100644 index 0000000..f5fb3b3 --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m @@ -0,0 +1,282 @@ +// Copyright 2017 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 <XCTest/XCTest.h> + +#import "FIRStorageMetadata.h" +#import "FIRStorageMetadata_Private.h" +#import "FIRStorageUtils.h" + +@interface FIRStorageMetadataTests : XCTestCase + +@end + +@implementation FIRStorageMetadataTests + +- (void)testInitialzeNoMetadata { + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:@{}]; + XCTAssertNotNil(metadata); +} + +- (void)testInitialzeFullMetadata { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataCacheControl : @"max-age=3600, no-cache", + kFIRStorageMetadataContentDisposition : @"inline", + kFIRStorageMetadataContentEncoding : @"gzip", + kFIRStorageMetadataContentLanguage : @"en-us", + kFIRStorageMetadataContentType : @"application/octet-stream", + kFIRStorageMetadataCustomMetadata : @{@"foo" : @{@"bar" : @"baz"}}, + kFIRStorageMetadataDownloadTokens : @"1234567890", + kFIRStorageMetadataGeneration : @"12345", + kFIRStorageMetadataMetageneration : @"67890", + kFIRStorageMetadataName : @"path/to/object", + kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108Z", + kFIRStorageMetadataUpdated : @"2016-03-01T20:16:01.673Z" + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata); + XCTAssertEqualObjects(metadata.bucket, metaDict[kFIRStorageMetadataBucket]); + XCTAssertEqualObjects(metadata.cacheControl, metaDict[kFIRStorageMetadataCacheControl]); + XCTAssertEqualObjects(metadata.contentDisposition, + metaDict[kFIRStorageMetadataContentDisposition]); + XCTAssertEqualObjects(metadata.contentEncoding, metaDict[kFIRStorageMetadataContentEncoding], ); + XCTAssertEqualObjects(metadata.contentType, metaDict[kFIRStorageMetadataContentType]); + XCTAssertEqualObjects(metadata.customMetadata, metaDict[kFIRStorageMetadataCustomMetadata]); + NSString *URLFormat = @"https://firebasestorage.googleapis.com/v0/b/%@/o/%@?alt=media&token=%@"; + NSString *URLString = [NSString + stringWithFormat:URLFormat, metaDict[kFIRStorageMetadataBucket], + [FIRStorageUtils GCSEscapedString:metaDict[kFIRStorageMetadataName]], + metaDict[kFIRStorageMetadataDownloadTokens]]; + XCTAssertEqualObjects([metadata.downloadURL description], URLString); + NSString *generation = [NSString stringWithFormat:@"%lld", metadata.generation]; + XCTAssertEqualObjects(generation, metaDict[kFIRStorageMetadataGeneration]); + NSString *metageneration = [NSString stringWithFormat:@"%lld", metadata.metageneration]; + XCTAssertEqualObjects(metageneration, metaDict[kFIRStorageMetadataMetageneration]); + XCTAssertEqualObjects(metadata.path, metaDict[kFIRStorageMetadataName]); + XCTAssertEqualObjects([metadata RFC3339StringFromDate:metadata.timeCreated], + metaDict[kFIRStorageMetadataTimeCreated]); + XCTAssertEqualObjects([metadata RFC3339StringFromDate:metadata.updated], + metaDict[kFIRStorageMetadataUpdated]); +} + +- (void)testDictionaryRepresentation { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataCacheControl : @"max-age=3600, no-cache", + kFIRStorageMetadataContentDisposition : @"inline", + kFIRStorageMetadataContentEncoding : @"gzip", + kFIRStorageMetadataContentLanguage : @"en-us", + kFIRStorageMetadataContentType : @"application/octet-stream", + kFIRStorageMetadataCustomMetadata : @{@"foo" : @{@"bar" : @"baz"}}, + kFIRStorageMetadataDownloadTokens : @"1234567890", + kFIRStorageMetadataGeneration : @"12345", + kFIRStorageMetadataMetageneration : @"67890", + kFIRStorageMetadataName : @"path/to/object", + kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108Z", + kFIRStorageMetadataUpdated : @"2016-03-01T20:16:01.673Z" + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + NSDictionary *dictRepresentation = [metadata dictionaryRepresentation]; + XCTAssertNotEqual(dictRepresentation, nil); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataBucket], + metaDict[kFIRStorageMetadataBucket]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataCacheControl], + metaDict[kFIRStorageMetadataCacheControl]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataContentDisposition], + metaDict[kFIRStorageMetadataContentDisposition]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataContentEncoding], + metaDict[kFIRStorageMetadataContentEncoding]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataContentLanguage], + metaDict[kFIRStorageMetadataContentLanguage]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataContentType], + metaDict[kFIRStorageMetadataContentType]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataCustomMetadata], + metaDict[kFIRStorageMetadataCustomMetadata]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataDownloadTokens], + metaDict[kFIRStorageMetadataDownloadTokens]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataGeneration], + metaDict[kFIRStorageMetadataGeneration]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataMetageneration], + metaDict[kFIRStorageMetadataMetageneration]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataName], + metaDict[kFIRStorageMetadataName]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataTimeCreated], + metaDict[kFIRStorageMetadataTimeCreated]); + XCTAssertEqualObjects(dictRepresentation[kFIRStorageMetadataUpdated], + metaDict[kFIRStorageMetadataUpdated]); +} + +- (void)testInitialzeNoDownloadTokensGetToken { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata); + XCTAssertEqual(metadata.downloadURL, nil); + XCTAssertEqual(metadata.downloadURLs, nil); +} + +- (void)testInitialzeMultipleDownloadTokensGetToken { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataDownloadTokens : @"12345,67890", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata); + NSString *URLformat = @"https://firebasestorage.googleapis.com/v0/b/%@/o/%@?alt=media&token=%@"; + NSString *URLString0 = [NSString + stringWithFormat:URLformat, metaDict[kFIRStorageMetadataBucket], + [FIRStorageUtils GCSEscapedString:metaDict[kFIRStorageMetadataName]], + @"12345"]; + NSString *URLString1 = [NSString + stringWithFormat:URLformat, metaDict[kFIRStorageMetadataBucket], + [FIRStorageUtils GCSEscapedString:metaDict[kFIRStorageMetadataName]], + @"67890"]; + XCTAssertEqualObjects([metadata.downloadURL absoluteString], URLString0); + XCTAssertEqualObjects([metadata.downloadURLs[0] absoluteString], URLString0); + XCTAssertEqualObjects([metadata.downloadURLs[1] absoluteString], URLString1); +} + +- (void)testMultipleDownloadURLsGetToken { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + NSString *URLformat = @"https://firebasestorage.googleapis.com/v0/b/%@/o/%@?alt=media&token=%@"; + NSString *URLString0 = [NSString + stringWithFormat:URLformat, metaDict[kFIRStorageMetadataBucket], + [FIRStorageUtils GCSEscapedString:metaDict[kFIRStorageMetadataName]], + @"12345"]; + NSString *URLString1 = [NSString + stringWithFormat:URLformat, metaDict[kFIRStorageMetadataBucket], + [FIRStorageUtils GCSEscapedString:metaDict[kFIRStorageMetadataName]], + @"67890"]; + NSURL *URL0 = [NSURL URLWithString:URLString0]; + NSURL *URL1 = [NSURL URLWithString:URLString1]; + NSArray *downloadURLs = @[ URL0, URL1 ]; + [metadata setValue:downloadURLs forKey:@"downloadURLs"]; + NSDictionary *newMetaDict = metadata.dictionaryRepresentation; + XCTAssertEqualObjects(newMetaDict[kFIRStorageMetadataDownloadTokens], @"12345,67890"); +} + +- (void)testInitialzeMetadataWithFile { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/file", + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + [metadata setType:FIRStorageMetadataTypeFile]; + XCTAssertEqual(metadata.isFile, YES); + XCTAssertEqual(metadata.isFolder, NO); +} + +- (void)testInitialzeMetadataWithFolder { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/folder/", + }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + [metadata setType:FIRStorageMetadataTypeFolder]; + XCTAssertEqual(metadata.isFolder, YES); + XCTAssertEqual(metadata.isFile, NO); +} + +- (void)testReflexiveMetadataEquality { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata0 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + FIRStorageMetadata *metadata1 = metadata0; + XCTAssertEqual(metadata0, metadata1); + XCTAssertEqualObjects(metadata0, metadata1); +} + +- (void)testNonsenseMetadataEquality { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata0 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotEqualObjects(metadata0, @"I'm not object metadata!"); +} + +- (void)testMetadataEquality { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata0 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + FIRStorageMetadata *metadata1 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotEqual(metadata0, metadata1); + XCTAssertEqualObjects(metadata0, metadata1); +} + +- (void)testMetadataCopy { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata0 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + FIRStorageMetadata *metadata1 = [metadata0 copy]; + XCTAssertNotEqual(metadata0, metadata1); + XCTAssertEqualObjects(metadata0, metadata1); +} + +- (void)testMetadataHashEquality { + NSDictionary *metaDict = @{ + kFIRStorageMetadataBucket : @"bucket", + kFIRStorageMetadataName : @"path/to/object", + }; + FIRStorageMetadata *metadata0 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + FIRStorageMetadata *metadata1 = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotEqual(metadata0, metadata1); + XCTAssertEqual([metadata0 hash], [metadata1 hash]); +} + +- (void)testZuluTimeOffset { + NSDictionary *metaDict = @{ kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108Z" }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata.timeCreated); +} + +- (void)testZuluZeroTimeOffset { + NSDictionary *metaDict = @{ kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108+0000" }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata.timeCreated); +} + +- (void)testGoogleStandardTimeOffset { + NSDictionary *metaDict = @{ kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108-0700" }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata.timeCreated); +} + +- (void)testUnspecifiedTimeOffset { + NSDictionary *metaDict = @{ kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108-0000" }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNotNil(metadata.timeCreated); +} + +- (void)testNoTimeOffset { + NSDictionary *metaDict = @{ kFIRStorageMetadataTimeCreated : @"1992-08-07T17:22:53.108" }; + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:metaDict]; + XCTAssertNil(metadata.timeCreated); +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStoragePathTests.m b/Example/Storage/Tests/Unit/FIRStoragePathTests.m new file mode 100644 index 0000000..017f41d --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStoragePathTests.m @@ -0,0 +1,234 @@ +// Copyright 2017 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 <XCTest/XCTest.h> + +#import "FIRStoragePath.h" + +@interface FIRStoragePathTests : XCTestCase + +@end + +@implementation FIRStoragePathTests + +- (void)testGSURI { + FIRStoragePath *path = [FIRStoragePath pathFromString:@"gs://bucket/path/to/object"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertEqualObjects(path.object, @"path/to/object"); +} + +- (void)testHTTPURL { + NSString *httpURL = + @"http://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object?token=signed_url_params"; + FIRStoragePath *path = [FIRStoragePath pathFromString:httpURL]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertEqualObjects(path.object, @"path/to/object"); +} + +- (void)testGSURINoPath { + FIRStoragePath *path = [FIRStoragePath pathFromString:@"gs://bucket/"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertNil(path.object); +} + +- (void)testHTTPURLNoPath { + FIRStoragePath *path = + [FIRStoragePath pathFromString:@"http://firebasestorage.googleapis.com/v0/b/bucket/"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertNil(path.object); +} + +- (void)testGSURINoTrailingSlash { + FIRStoragePath *path = [FIRStoragePath pathFromString:@"gs://bucket"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertNil(path.object); +} + +- (void)testHTTPURLNoTrailingSlash { + FIRStoragePath *path = + [FIRStoragePath pathFromString:@"http://firebasestorage.googleapis.com/v0/b/bucket"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertNil(path.object); +} + +- (void)testGSURIPercentEncoding { + FIRStoragePath *path = [FIRStoragePath pathFromString:@"gs://bucket/?/%/#"]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertEqualObjects(path.object, @"?/%/#"); +} + +- (void)testHTTPURLPercentEncoding { + NSString *httpURL = + @"http://firebasestorage.googleapis.com/v0/b/bucket/o/%3F/%25/%23?token=signed_url_params"; + FIRStoragePath *path = [FIRStoragePath pathFromString:httpURL]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertEqualObjects(path.object, @"?/%/#"); +} + +- (void)testHTTPURLNoToken { + NSString *httpURL = @"http://firebasestorage.googleapis.com/v0/b/bucket/o/%23hashtag/no/token"; + FIRStoragePath *path = [FIRStoragePath pathFromString:httpURL]; + XCTAssertEqualObjects(path.bucket, @"bucket"); + XCTAssertEqualObjects(path.object, @"#hashtag/no/token"); +} + +- (void)testGSURIThrowsOnNoBucket { + XCTAssertThrows([FIRStoragePath pathFromString:@"gs://"]); +} + +- (void)testHTTPURLThrowsOnNoBucket { + XCTAssertThrows([FIRStoragePath pathFromString:@"http://firebasestorage.googleapis.com/"]); +} + +- (void)testThrowsOnInvalidScheme { + NSString *ftpURL = @"ftp://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object"; + XCTAssertThrows([FIRStoragePath pathFromString:ftpURL]); +} + +- (void)testHTTPURLNilIncorrectHost { + NSString *httpURL = @"http://foo.google.com/v0/b/bucket/o/%3F/%25/%23?token=signed_url_params"; + XCTAssertThrows([FIRStoragePath pathFromString:httpURL]); +} + +- (void)testchildToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"object"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/object"); +} + +- (void)testChildByAppendingNilToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:nil]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/"); +} + +- (void)testChildByAppendingNoPathToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@""]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/"); +} + +- (void)testChildByAppendingLeadingSlashChildToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"/object"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/object"); +} + +- (void)testChildByAppendingTrailingSlashChildToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"object/"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/object"); +} + +- (void)testChildByAppendingLeadingAndTrailingSlashChildToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"/object/"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/object"); +} + +- (void)testChildByAppendingMultipleChildrenToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"path/to/object"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testChildByAppendingMultipleChildrenWithMultipleSlashesToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"/path//to///object////"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testChildByAppendingOnlySlashesToRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *childPath = [path child:@"//////////"]; + XCTAssertEqualObjects([childPath stringValue], @"gs://bucket/"); +} + +- (void)testParentAtRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *parent = [path parent]; + XCTAssertNil(parent); +} + +- (void)testParentChildPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + FIRStoragePath *parent = [path parent]; + XCTAssertEqualObjects([parent stringValue], @"gs://bucket/path/to"); +} + +- (void)testParentChildPathSlashes { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"/path//to///"]; + FIRStoragePath *parent = [path parent]; + XCTAssertEqualObjects([parent stringValue], @"gs://bucket/path"); +} + +- (void)testParentChildPathOnlySlashs { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"/////"]; + FIRStoragePath *parent = [path parent]; + XCTAssertNil(parent); +} + +- (void)testRootAtRoot { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *root = [path root]; + XCTAssertEqualObjects([root stringValue], @"gs://bucket/"); +} + +- (void)testRootAtChildPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + FIRStoragePath *root = [path root]; + XCTAssertEqualObjects([root stringValue], @"gs://bucket/"); +} + +- (void)testRootAtSlashPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"//////////"]; + FIRStoragePath *root = [path root]; + XCTAssertEqualObjects([root stringValue], @"gs://bucket/"); +} + +- (void)testCopy { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"object"]; + FIRStoragePath *copiedPath = [path copy]; + XCTAssertNotEqual(copiedPath, path); + XCTAssertEqualObjects(copiedPath, path); +} + +- (void)testCopyNoBucket { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:nil object:@"object"]; +#pragma clang diagnostic pop + FIRStoragePath *copiedPath = [path copy]; + XCTAssertNotEqual(copiedPath, path); + XCTAssertEqualObjects(copiedPath, path); +} + +- (void)testCopyNoObject { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStoragePath *copiedPath = [path copy]; + XCTAssertNotEqual(copiedPath, path); + XCTAssertEqualObjects(copiedPath, path); +} + +- (void)testCopyNothing { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:nil object:nil]; +#pragma clang diagnostic pop + FIRStoragePath *copiedPath = [path copy]; + XCTAssertNotEqual(copiedPath, path); + XCTAssertEqualObjects(copiedPath, path); +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageReferenceTests.m b/Example/Storage/Tests/Unit/FIRStorageReferenceTests.m new file mode 100644 index 0000000..e54896c --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageReferenceTests.m @@ -0,0 +1,163 @@ +// Copyright 2017 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 "FirebaseStorage.h" + +#import "FIRStorageReference_Private.h" +#import "FIRStorageTestHelpers.h" + +@interface FIRStorageReferenceTests : XCTestCase + +@property(strong, nonatomic) FIRStorage *storage; + +@end + +@implementation FIRStorageReferenceTests + +- (void)setUp { + [super setUp]; + + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); + + id mockApp = OCMClassMock([FIRApp class]); + OCMStub([mockApp name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)mockApp options]).andReturn(mockOptions); + self.storage = [FIRStorage storageForApp:mockApp]; +} + +- (void)tearDown { + self.storage = nil; + [super tearDown]; +} + +- (void)testRoot { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object"]; + XCTAssertEqualObjects([ref.root stringValue], @"gs://bucket/"); +} + +- (void)testRootWithNoPath { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + XCTAssertEqualObjects([ref.root stringValue], @"gs://bucket/"); +} + +- (void)testSingleChild { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *childRef = [ref child:@"path"]; + XCTAssertEqualObjects([childRef stringValue], @"gs://bucket/path"); +} + +- (void)testMultipleChildrenSingleString { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *childRef = [ref child:@"path/to/object"]; + XCTAssertEqualObjects([childRef stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testMultipleChildrenMultipleStrings { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *childRef = [ref child:@"path"]; + childRef = [childRef child:@"to"]; + childRef = [childRef child:@"object"]; + XCTAssertEqualObjects([childRef stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testSameChildDifferentRef { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *firstRef = [ref child:@"1"]; + FIRStorageReference *secondRef = [ref child:@"1"]; + XCTAssertEqualObjects([ref stringValue], @"gs://bucket/"); + XCTAssertEqualObjects(firstRef, secondRef); + XCTAssertNotEqual(firstRef, secondRef); +} + +- (void)testDifferentChildDifferentRef { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *firstRef = [ref child:@"1"]; + FIRStorageReference *secondRef = [ref child:@"2"]; + XCTAssertEqualObjects([ref stringValue], @"gs://bucket/"); + XCTAssertNotEqual(firstRef, secondRef); +} + +- (void)testChildWithTrailingSlash { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object/"]; + XCTAssertEqualObjects([ref stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testChildWithLeadingSlash { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket//path/to/object/"]; + XCTAssertEqualObjects([ref stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testChildCompressSlashes { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket//path///to////object////"]; + XCTAssertEqualObjects([ref stringValue], @"gs://bucket/path/to/object"); +} + +- (void)testParent { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object"]; + FIRStorageReference *parentRef = [ref parent]; + XCTAssertEqualObjects([parentRef stringValue], @"gs://bucket/path/to"); +} + +- (void)testParentToRoot { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path"]; + FIRStorageReference *parentRef = [ref parent]; + XCTAssertEqualObjects([parentRef stringValue], @"gs://bucket/"); +} + +- (void)testParentToRootTrailingSlash { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/"]; + FIRStorageReference *parentRef = [ref parent]; + XCTAssertEqualObjects([parentRef stringValue], @"gs://bucket/"); +} + +- (void)testParentAtRoot { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *parentRef = [ref parent]; + XCTAssertNil(parentRef); +} + +- (void)testBucket { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object"]; + XCTAssertEqualObjects(ref.bucket, @"bucket"); +} + +- (void)testName { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object"]; + XCTAssertEqualObjects(ref.name, @"object"); +} + +- (void)testNameNoObject { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + XCTAssertEqualObjects(ref.name, @""); +} + +- (void)testFullPath { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/path/to/object"]; + XCTAssertEqualObjects(ref.fullPath, @"path/to/object"); +} + +- (void)testFullPathNoObject { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + XCTAssertEqualObjects(ref.fullPath, @""); +} + +- (void)testCopy { + FIRStorageReference *ref = [self.storage referenceForURL:@"gs://bucket/"]; + FIRStorageReference *copiedRef = [ref copy]; + XCTAssertEqualObjects(ref, copiedRef); + XCTAssertNotEqual(ref, copiedRef); +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageTestHelpers.h b/Example/Storage/Tests/Unit/FIRStorageTestHelpers.h new file mode 100644 index 0000000..4489c07 --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageTestHelpers.h @@ -0,0 +1,127 @@ +/* + * Copyright 2017 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 "FIRAppInternal.h" + +#import <Foundation/Foundation.h> +#import <OCMock/OCMock.h> +#import <XCTest/XCTest.h> + +#import "FIRApp.h" +#import "FIROptions.h" + +#import "FIRStorageConstants.h" +#import "FIRStorageConstants_Private.h" +#import "FIRStorageErrors.h" +#import "FIRStorageMetadata.h" +#import "FIRStorageReference.h" +#import "FIRStorageReference_Private.h" +#import "FIRStorageTask.h" +#import "FIRStorageTask_Private.h" +#import "FIRStorageTokenAuthorizer.h" +#import "FIRStorageUtils.h" + +#import <GTMSessionFetcher/GTMSessionFetcher.h> + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kGoogleHTTPErrorDomain; +FOUNDATION_EXPORT NSString *const kHTTPVersion; +FOUNDATION_EXPORT NSString *const kUnauthenticatedResponseString; +FOUNDATION_EXPORT NSString *const kUnauthorizedResponseString; +FOUNDATION_EXPORT NSString *const kNotFoundResponseString; +FOUNDATION_EXPORT NSString *const kInvalidJSONResponseString; +FOUNDATION_EXPORT NSString *const kFIRStorageValidURL; +FOUNDATION_EXPORT NSString *const kFIRStorageNotFoundURL; +FOUNDATION_EXPORT NSString *const kFIRStorageTestAuthToken; +FOUNDATION_EXPORT NSString *const kFIRStorageAppName; + +/** + * Standard timeout for all async tests. + */ +static NSTimeInterval kExpectationTimeoutSeconds = 10; + +@interface FIRStorageTestHelpers : NSObject + +/** + * Returns a valid URL for an object stored. + */ ++ (NSURL *)objectURL; + +/** + * Returns a valid URL for a bucket. + */ ++ (NSURL *)bucketURL; + +/** + * Returns a valid URL for an object not found in the current storage bucket. + */ ++ (NSURL *)notFoundURL; + +/** + * Returns a valid FIRStoragePath for an object stored. + */ ++ (FIRStoragePath *)objectPath; + +/** + * Returns a valid FIRStoragePath for a bucket (no object). + */ ++ (FIRStoragePath *)bucketPath; + +/** + * Returns a valid FIRStoragePath for an object not found in the current storage bucket. + */ ++ (FIRStoragePath *)notFoundPath; + +/** + * Returns a successful response block. + */ ++ (GTMSessionFetcherTestBlock)successBlock; + +/** + * Returns a successful response block containing object metadata. + * @param metadata Metadata returned in the request. + */ ++ (GTMSessionFetcherTestBlock)successBlockWithMetadata:(nullable FIRStorageMetadata *)metadata; + +/** + * Returns a unsuccessful response block due to improper authentication. + */ ++ (GTMSessionFetcherTestBlock)unauthenticatedBlock; + +/** + * Returns a unsuccessful response block due to improper authorization. + */ ++ (GTMSessionFetcherTestBlock)unauthorizedBlock; + +/** + * Returns a unsuccessful response block due the object not being found. + */ ++ (GTMSessionFetcherTestBlock)notFoundBlock; + +/** + * Returns a unsuccessful response block due invalid JSON returned by the server. + */ ++ (GTMSessionFetcherTestBlock)invalidJSONBlock; + +/** + * Waits for the given test case to time out by wrapping -waitForExpectation. + */ ++ (void)waitForExpectation:(id)test; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Storage/Tests/Unit/FIRStorageTestHelpers.m b/Example/Storage/Tests/Unit/FIRStorageTestHelpers.m new file mode 100644 index 0000000..fef67ef --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageTestHelpers.m @@ -0,0 +1,128 @@ +// Copyright 2017 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 "FIRStorageTestHelpers.h" + +NSString *const kGoogleHTTPErrorDomain = @"com.google.HTTPStatus"; +NSString *const kHTTPVersion = @"HTTP/1.1"; +NSString *const kUnauthenticatedResponseString = + @"<html><body><p>User not authenticated. Authentication via Authorization header required. " + @"Authorization Header does not match expected format of 'Authorization: Firebase " + @"<JWT>'.</p></body></html>"; +NSString *const kUnauthorizedResponseString = + @"<html><body><p>User not authorized. Authentication via Authorization header required. " + @"Authorization Header does not match expected format of 'Authorization: Firebase " + @"<JWT>'.</p></body></html>"; +NSString *const kNotFoundResponseString = @"<html><body><p>Object not found.</p></body></html>"; +NSString *const kInvalidJSONResponseString = @"This is not a JSON object"; +NSString *const kFIRStorageObjectURL = + @"https://firebasestorage.googleapis.com/v0/b/bucket/o/object"; +NSString *const kFIRStorageBucketURL = @"https://firebasestorage.googleapis.com/v0/b/bucket/o"; +NSString *const kFIRStorageNotFoundURL = + @"https://firebasestorage.googleapis.com/v0/b/bucket/o/i/dont/exist"; +NSString *const kFIRStorageTestAuthToken = @"1234-5678-9012-3456-7890"; +NSString *const kFIRStorageAppName = @"app"; + +@implementation FIRStorageTestHelpers + ++ (NSURL *)objectURL { + return [NSURL URLWithString:kFIRStorageObjectURL]; +} + ++ (NSURL *)bucketURL { + return [NSURL URLWithString:kFIRStorageBucketURL]; +} + ++ (NSURL *)notFoundURL { + return [NSURL URLWithString:kFIRStorageNotFoundURL]; +} + ++ (FIRStoragePath *)objectPath { + return [FIRStoragePath pathFromString:kFIRStorageObjectURL]; +} + ++ (FIRStoragePath *)bucketPath { + return [FIRStoragePath pathFromString:kFIRStorageBucketURL]; +} + ++ (FIRStoragePath *)notFoundPath { + return [FIRStoragePath pathFromString:kFIRStorageNotFoundURL]; +} + ++ (GTMSessionFetcherTestBlock)successBlock { + return [FIRStorageTestHelpers successBlockWithMetadata:nil]; +} + ++ (GTMSessionFetcherTestBlock)successBlockWithMetadata:(nullable FIRStorageMetadata *)metadata { + NSData *data; + if (metadata) { + data = [NSData frs_dataFromJSONDictionary:[metadata dictionaryRepresentation]]; + } + return [FIRStorageTestHelpers blockForData:data statusCode:200]; +} + ++ (GTMSessionFetcherTestBlock)unauthenticatedBlock { + NSData *data = [kUnauthenticatedResponseString dataUsingEncoding:NSUTF8StringEncoding]; + return [FIRStorageTestHelpers blockForData:data statusCode:401]; +} + ++ (GTMSessionFetcherTestBlock)unauthorizedBlock { + NSData *data = [kUnauthorizedResponseString dataUsingEncoding:NSUTF8StringEncoding]; + return [FIRStorageTestHelpers blockForData:data statusCode:403]; +} + ++ (GTMSessionFetcherTestBlock)notFoundBlock { + NSData *data = [kNotFoundResponseString dataUsingEncoding:NSUTF8StringEncoding]; + return [FIRStorageTestHelpers blockForData:data statusCode:404]; +} + ++ (GTMSessionFetcherTestBlock)invalidJSONBlock { + NSData *data = [kInvalidJSONResponseString dataUsingEncoding:NSUTF8StringEncoding]; + return [FIRStorageTestHelpers blockForData:data statusCode:200]; +} + +#pragma mark - Private methods + ++ (GTMSessionFetcherTestBlock)blockForData:(nullable NSData *)data statusCode:(NSInteger)code { + GTMSessionFetcherTestBlock block = + ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:code + HTTPVersion:kHTTPVersion + headerFields:nil]; + NSError *error; + if (code >= 400) { + NSDictionary *userInfo; + if (data) { + userInfo = @{ @"data" : data }; + } + error = [NSError errorWithDomain:kGoogleHTTPErrorDomain code:code userInfo:userInfo]; + } + + response(httpResponse, data, error); + }; + return block; +} + ++ (void)waitForExpectation:(id)test { + [test waitForExpectationsWithTimeout:kExpectationTimeoutSeconds + handler:^(NSError *_Nullable error) { + if (error) { + NSLog(@"Error: %@", error); + } + }]; +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageTests.m b/Example/Storage/Tests/Unit/FIRStorageTests.m new file mode 100644 index 0000000..1b45295 --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageTests.m @@ -0,0 +1,214 @@ +// Copyright 2017 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 "FIRStorageTestHelpers.h" + +#import "FIRStorageReference.h" +#import "FIRStorageReference_Private.h" +#import "FIRStorage_Private.h" + +@interface FIRStorageTests : XCTestCase + +@property(strong, nonatomic) id app; + +@end + +@implementation FIRStorageTests + +- (void)setUp { + [super setUp]; + + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); + + self.app = OCMClassMock([FIRApp class]); + OCMStub([self.app name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)self.app options]).andReturn(mockOptions); +} + +- (void)tearDown { + self.app = nil; + [super tearDown]; +} + +- (void)testBucketNotEnforced { + FIROptions * mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@""); + FIRApp *app = OCMClassMock([FIRApp class]); + OCMStub([app name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)app options]).andReturn(mockOptions); + + FIRStorage *storage = [FIRStorage storageForApp:app]; + [storage referenceForURL:@"gs://benwu-test1.storage.firebase.com/child"]; + [storage referenceForURL:@"gs://benwu-test2.storage.firebase.com/child"]; +} + +- (void)testBucketEnforced { + FIRStorage *storage = [FIRStorage storageForApp:self.app + URL:@"gs://benwu-test1.storage.firebase.com"]; + [storage referenceForURL:@"gs://benwu-test1.storage.firebase.com/child"]; + storage = [FIRStorage 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 { + FIRStorage *storage = [FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; + XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[storage reference] description]); + storage = [FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com/"]; + XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[storage reference] description]); +} + +- (void) testInitWithWrongScheme { + XCTAssertThrows([FIRStorage storageForApp:self.app URL:@"http://foo-bar.appspot.com"]); +} + +- (void) testInitWithNoScheme { + XCTAssertThrows([FIRStorage storageForApp:self.app URL:@"foo-bar.appspot.com"]); +} + +- (void) testInitWithNilURL { + XCTAssertThrows([FIRStorage storageForApp:self.app URL:nil]); +} + +- (void) testInitWithPath { + XCTAssertThrows([FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com/child"]); +} + +- (void) testInitWithDefaultAndCustomUrl { + FIRStorage *customInstance = [FIRStorage storageForApp:self.app + URL:@"gs://foo-bar.appspot.com"]; + FIRStorage *defaultInstance = [FIRStorage storageForApp:self.app]; + XCTAssertEqualObjects(@"gs://foo-bar.appspot.com/", [[customInstance reference] description]); + XCTAssertEqualObjects(@"gs://bucket/", [[defaultInstance reference] description]); +} + +- (void)testStorageDefaultApp { + FIRStorage *storage = [FIRStorage storageForApp:self.app]; + XCTAssertEqualObjects(storage.app.name, ((FIRApp *)self.app).name); + XCTAssertNotNil(storage.fetcherServiceForApp); +} + +- (void)testStorageCustomApp { + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); + id secondApp = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRStorage *storage = [FIRStorage storageForApp:secondApp]; + XCTAssertNotEqual(storage.app.name, ((FIRApp *)self.app).name); + XCTAssertNotNil(storage.fetcherServiceForApp); + XCTAssertNotEqualObjects(storage.fetcherServiceForApp, + [FIRStorage storageForApp:self.app].fetcherServiceForApp); +} + +- (void)testStorageNoBucketInConfig { + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(nil); + id secondApp = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + XCTAssertThrows([FIRStorage storageForApp:secondApp]); +} + +- (void)testStorageEmptyBucketInConfig { + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@""); + id secondApp = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRStorage *storage = [FIRStorage storageForApp:secondApp]; + FIRStorageReference *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 = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRStorage *storage = [FIRStorage storageForApp:secondApp]; + XCTAssertEqualObjects([(FIRApp *)secondApp options].storageBucket, @"notMyBucket"); + XCTAssertThrows([storage referenceForURL:@"gs://bucket/path/to/object"]); +} + +- (void)testRefDefaultApp { + FIRStorageReference *convenienceRef = + [[FIRStorage storageForApp:self.app] referenceForURL:@"gs://bucket/path/to/object"]; + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + FIRStorageReference *builtRef = + [[FIRStorageReference alloc] initWithStorage:[FIRStorage storageForApp:self.app] path:path]; + XCTAssertEqualObjects([convenienceRef description], [builtRef description]); + XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); +} + +- (void)testRefCustomApp { + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); + id secondApp = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRStorageReference *convenienceRef = + [[FIRStorage storageForApp:secondApp] referenceForURL:@"gs://bucket/path/to/object"]; + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + FIRStorageReference *builtRef = + [[FIRStorageReference alloc] initWithStorage:[FIRStorage storageForApp:secondApp] path:path]; + XCTAssertEqualObjects([convenienceRef description], [builtRef description]); + XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); +} + +- (void)testRootRefDefaultApp { + FIRStorageReference *convenienceRef = [[FIRStorage storageForApp:self.app] reference]; + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + FIRStorageReference *builtRef = + [[FIRStorageReference alloc] initWithStorage:[FIRStorage storageForApp:self.app] path:path]; + XCTAssertEqualObjects([convenienceRef description], [builtRef description]); + XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); +} + +- (void)testRefWithPathDefaultApp { + FIRStorageReference *convenienceRef = + [[FIRStorage storageForApp:self.app] referenceWithPath:@"path/to/object"]; + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + FIRStorageReference *builtRef = + [[FIRStorageReference alloc] initWithStorage:[FIRStorage storageForApp:self.app] path:path]; + XCTAssertEqualObjects([convenienceRef description], [builtRef description]); + XCTAssertEqualObjects(convenienceRef.storage.app, builtRef.storage.app); +} + +- (void)testEqual { + FIRStorage *storage = [FIRStorage storageForApp:self.app]; + FIRStorage *copy = [storage copy]; + XCTAssertEqualObjects(storage.app.name, copy.app.name); +} + +- (void)testNotEqual { + FIRStorage *storage = [FIRStorage storageForApp:self.app]; + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket"); + id secondApp = OCMClassMock([FIRApp class]); + OCMStub([secondApp name]).andReturn(@"secondApp"); + OCMStub([(FIRApp *)secondApp options]).andReturn(mockOptions); + FIRStorage *secondStorage = [FIRStorage storageForApp:secondApp]; + XCTAssertNotEqualObjects(storage, secondStorage); +} + +- (void)testHash { + FIRStorage *storage = [FIRStorage storageForApp:self.app]; + FIRStorage *copy = [storage copy]; + XCTAssertEqual([storage hash], [copy hash]); +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageTokenAuthorizerTests.m b/Example/Storage/Tests/Unit/FIRStorageTokenAuthorizerTests.m new file mode 100644 index 0000000..e98ffbb --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageTokenAuthorizerTests.m @@ -0,0 +1,226 @@ +// Copyright 2017 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 "FIRStorageTestHelpers.h" + +@interface FIRStorageTokenAuthorizerTests : XCTestCase + +@property(strong, nonatomic) GTMSessionFetcher *fetcher; +@property(strong, nonatomic) id mockApp; + +@end + +@implementation FIRStorageTokenAuthorizerTests + +- (void)setUp { + [super setUp]; + NSURLRequest *fetchRequest = [NSURLRequest requestWithURL:[FIRStorageTestHelpers objectURL]]; + self.fetcher = [GTMSessionFetcher fetcherWithRequest:fetchRequest]; + + self.mockApp = OCMClassMock([FIRApp class]); + OCMStub([self.mockApp getTokenImplementation]) + .andReturn(^{ + }); + FIRTokenCallback mockCallback = + [OCMArg invokeBlockWithArgs:kFIRStorageTestAuthToken, [NSNull null], nil]; + OCMStub([self.mockApp getTokenForcingRefresh:NO withCallback:mockCallback]); + GTMSessionFetcherService *fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcher.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:self.mockApp fetcherService:fetcherService]; +} + +- (void)tearDown { + self.fetcher = nil; + self.mockApp = nil; + [super tearDown]; +} + +- (void)testSuccessfulAuth { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulAuth"]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertTrue([self.fetcher.authorizer isAuthorizedRequest:fetcher.request]); +#pragma clang diagnostic pop + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + [self.fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, + NSError *_Nullable error) { + NSDictionary<NSString *, NSString *> *headers = self.fetcher.request.allHTTPHeaderFields; + NSString *authHeader = [headers objectForKey:@"Authorization"]; + NSString *firebaseToken = + [NSString stringWithFormat:kFIRStorageAuthTokenFormat, kFIRStorageTestAuthToken]; + XCTAssertEqualObjects(authHeader, firebaseToken); + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulAuth { + XCTestExpectation *expectation = [self expectationWithDescription:@"testUnsuccessfulAuth"]; + + NSError *authError = [NSError errorWithDomain:FIRStorageErrorDomain + code:FIRStorageErrorCodeUnauthenticated + userInfo:nil]; + id unsuccessfulApp = OCMClassMock([FIRApp class]); + OCMStub([unsuccessfulApp getTokenImplementation]) + .andReturn(^{ + }); + FIRTokenCallback mockCallback = [OCMArg invokeBlockWithArgs:[NSNull null], authError, nil]; + OCMStub([unsuccessfulApp getTokenForcingRefresh:NO withCallback:mockCallback]); + GTMSessionFetcherService *fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcher.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:unsuccessfulApp fetcherService:fetcherService]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertEqual([self.fetcher.authorizer isAuthorizedRequest:fetcher.request], NO); +#pragma cland diagnostic pop + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:401 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, authError); + }; + + [self.fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, + NSError *_Nullable error) { + NSDictionary<NSString *, NSString *> *headers = self.fetcher.request.allHTTPHeaderFields; + NSString *authHeader = [headers objectForKey:@"Authorization"]; + XCTAssertNil(authHeader); + XCTAssertEqualObjects(error.domain, FIRStorageErrorDomain); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthenticated); + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testSuccessfulUnauthenticatedAuth { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testSuccessfulUnauthenticatedAuth"]; + + // Note that self.mockApp is left with null properties--this simulates no token present + self.mockApp = OCMClassMock([FIRApp class]); + GTMSessionFetcherService *fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcher.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:self.mockApp fetcherService:fetcherService]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertFalse([self.fetcher.authorizer isAuthorizedRequest:fetcher.request]); +#pragma cland diagnostic pop + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + [self.fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, + NSError *_Nullable error) { + NSDictionary<NSString *, NSString *> *headers = self.fetcher.request.allHTTPHeaderFields; + NSString *authHeader = [headers objectForKey:@"Authorization"]; + XCTAssertNil(authHeader); + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testIsAuthorizing { + XCTestExpectation *expectation = [self expectationWithDescription:@"testIsAuthorizing"]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { + XCTAssertFalse([fetcher.authorizer isAuthorizingRequest:fetcher.request]); + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + [self.fetcher + beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testStopAuthorizingNoop { + XCTestExpectation *expectation = [self expectationWithDescription:@"testStopAuthorizingNoop"]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { + // Since both of these are noops, we expect that invoking them + // will still result in successful authentication + [fetcher.authorizer stopAuthorization]; + [fetcher.authorizer stopAuthorizationForRequest:fetcher.request]; + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + [self.fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, + NSError *_Nullable error) { + NSDictionary<NSString *, NSString *> *headers = self.fetcher.request.allHTTPHeaderFields; + NSString *authHeader = [headers objectForKey:@"Authorization"]; + NSString *firebaseToken = + [NSString stringWithFormat:kFIRStorageAuthTokenFormat, kFIRStorageTestAuthToken]; + XCTAssertEqualObjects(authHeader, firebaseToken); + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testEmail { + XCTestExpectation *expectation = [self expectationWithDescription:@"testEmail"]; + + self.fetcher.testBlock = ^(GTMSessionFetcher *fetcher, GTMSessionFetcherTestResponse response) { + XCTAssertNil([fetcher.authorizer userEmail]); + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + [self.fetcher + beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + [expectation fulfill]; + }]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m new file mode 100644 index 0000000..a85d181 --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m @@ -0,0 +1,199 @@ +// Copyright 2017 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 "FIRStorageTestHelpers.h" +#import "FIRStorageUpdateMetadataTask.h" + +@interface FIRStorageUpdateMetadataTests : XCTestCase + +@property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(strong, nonatomic) FIRStorageMetadata *metadata; +@property(strong, nonatomic) FIRStorage *storage; +@property(strong, nonatomic) id mockApp; + +@end + +@implementation FIRStorageUpdateMetadataTests + +- (void)setUp { + [super setUp]; + + NSDictionary *metadataDict = @{ @"bucket" : @"bucket", @"name" : @"path/to/object" }; + self.metadata = [[FIRStorageMetadata alloc] initWithDictionary:metadataDict]; + + id mockOptions = OCMClassMock([FIROptions class]); + OCMStub([mockOptions storageBucket]).andReturn(@"bucket.appspot.com"); + + self.mockApp = OCMClassMock([FIRApp class]); + OCMStub([self.mockApp name]).andReturn(kFIRStorageAppName); + OCMStub([(FIRApp *)self.mockApp options]).andReturn(mockOptions); + + self.fetcherService = [[GTMSessionFetcherService alloc] init]; + self.fetcherService.authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithApp:self.mockApp + fetcherService:self.fetcherService]; + + self.storage = [FIRStorage storageForApp:self.mockApp]; +} + +- (void)tearDown { + self.fetcherService = nil; + self.storage = nil; + self.mockApp = nil; + [super tearDown]; +} + +- (void)testFetcherConfiguration { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = ^(GTMSessionFetcher *fetcher, + GTMSessionFetcherTestResponse response) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + XCTAssertEqualObjects(fetcher.request.URL, [FIRStorageTestHelpers objectURL]); + XCTAssertEqualObjects(fetcher.request.HTTPMethod, @"PATCH"); + NSData *bodyData = [NSData frs_dataFromJSONDictionary:[self.metadata dictionaryRepresentation]]; + XCTAssertEqualObjects(fetcher.request.HTTPBody, bodyData); + NSDictionary *HTTPHeaders = fetcher.request.allHTTPHeaderFields; + XCTAssertEqualObjects(HTTPHeaders[@"Content-Type"], @"application/json; charset=UTF-8"); + XCTAssertEqualObjects(HTTPHeaders[@"Content-Length"], [@(bodyData.length) stringValue]); +#pragma clang diagnostic pop + NSHTTPURLResponse *httpResponse = + [[NSHTTPURLResponse alloc] initWithURL:fetcher.request.URL + statusCode:200 + HTTPVersion:kHTTPVersion + headerFields:nil]; + response(httpResponse, nil, nil); + }; + + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testSuccessfulFetch { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSuccessfulFetch"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers successBlockWithMetadata:self.metadata]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + XCTAssertEqualObjects(self.metadata.bucket, metadata.bucket); + XCTAssertEqualObjects(self.metadata.name, metadata.name); + XCTAssertNil(error); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthenticated { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthenticated"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthenticatedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + XCTAssertNil(metadata); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthenticated); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchUnauthorized { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchUnauthorized"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers unauthorizedBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + XCTAssertNil(metadata); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthorized); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchObjectDoesntExist { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchObjectDoesntExist"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers notFoundBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers notFoundPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + XCTAssertNil(metadata); + XCTAssertEqual(error.code, FIRStorageErrorCodeObjectNotFound); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +- (void)testUnsuccessfulFetchBadJSON { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnsuccessfulFetchBadJSON"]; + + self.fetcherService.testBlock = [FIRStorageTestHelpers invalidJSONBlock]; + FIRStoragePath *path = [FIRStorageTestHelpers objectPath]; + FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; + FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] + initWithReference:ref + fetcherService:self.fetcherService + metadata:self.metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + XCTAssertNil(metadata); + XCTAssertEqual(error.code, FIRStorageErrorCodeUnknown); + [expectation fulfill]; + }]; + [task enqueue]; + + [FIRStorageTestHelpers waitForExpectation:self]; +} + +@end diff --git a/Example/Storage/Tests/Unit/FIRStorageUtilsTests.m b/Example/Storage/Tests/Unit/FIRStorageUtilsTests.m new file mode 100644 index 0000000..8bf4c7e --- /dev/null +++ b/Example/Storage/Tests/Unit/FIRStorageUtilsTests.m @@ -0,0 +1,125 @@ +// Copyright 2017 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 <XCTest/XCTest.h> + +#import "FIRStorageUtils.h" + +#import "FIRStoragePath.h" + +@interface FIRStorageUtilsTests : XCTestCase + +@end + +@implementation FIRStorageUtilsTests + +- (void)testCommonExtensionToMIMEType { + NSDictionary<NSString *, NSString *> *extensionToMIMEType = @{ + @"txt" : @"text/plain", + @"png" : @"image/png", + @"mp3" : @"audio/mpeg", + @"mov" : @"video/quicktime", + @"gif" : @"image/gif" + }; + [extensionToMIMEType + enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull extension, NSString *_Nonnull MIMEType, + BOOL *_Nonnull stop) { + XCTAssertEqualObjects([FIRStorageUtils MIMETypeForExtension:extension], MIMEType); + }]; +} + +- (void)testParseGoodDataToDict { + NSString *JSONString = @"{\"hello\" : \"world\"}"; + NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *JSONDictionary = [NSDictionary frs_dictionaryFromJSONData:JSONData]; + NSDictionary *expectedDictionary = @{ @"hello" : @"world" }; + XCTAssertEqualObjects(JSONDictionary, expectedDictionary); +} + +- (void)testParseBadDataToDict { + NSString *JSONString = @"Invalid JSON Object"; + NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *JSONDictionary = [NSDictionary frs_dictionaryFromJSONData:JSONData]; + XCTAssertNil(JSONDictionary); +} + +- (void)testParseNilToDict { + NSDictionary *JSONDictionary = [NSDictionary frs_dictionaryFromJSONData:nil]; + XCTAssertNil(JSONDictionary); +} + +- (void)testParseGoodDictToData { + NSDictionary *JSONDictionary = @{ @"hello" : @"world" }; + NSData *expectedData = [NSData frs_dataFromJSONDictionary:JSONDictionary]; + NSString *JSONString = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding]; + NSString *expectedString = @"{\"hello\":\"world\"}"; + XCTAssertEqualObjects(JSONString, expectedString); +} + +- (void)testParseNilToData { + NSData *JSONData = [NSData frs_dataFromJSONDictionary:nil]; + XCTAssertNil(JSONData); +} + +- (void)testNilDictToQueryString { + NSDictionary *params; + NSString *queryString = [FIRStorageUtils queryStringForDictionary:params]; + XCTAssertEqualObjects(queryString, @""); +} + +- (void)testEmptyDictToQueryString { + NSDictionary *params = @{}; + NSString *queryString = [FIRStorageUtils queryStringForDictionary:params]; + XCTAssertEqualObjects(queryString, @""); +} + +- (void)testSingleItemToQueryString { + NSDictionary *params = @{ @"foo" : @"bar" }; + NSString *queryString = [FIRStorageUtils queryStringForDictionary:params]; + XCTAssertEqualObjects(queryString, @"foo=bar"); +} + +- (void)testMultiItemDictToQueryString { + NSDictionary *params = @{ @"foo" : @"bar", @"baz" : @"qux" }; + NSString *queryString = [FIRStorageUtils queryStringForDictionary:params]; + XCTAssertEqualObjects(queryString, @"foo=bar&baz=qux"); +} + +- (void)testDefaultRequestForFullPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + NSURLRequest *request = [FIRStorageUtils defaultRequestForPath:path]; + XCTAssertEqualObjects([request.URL absoluteString], + @"https://firebasestorage.googleapis.com/v0/b/bucket/o/path%2Fto%2Fobject"); +} + +- (void)testDefaultRequestForNoPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + NSURLRequest *request = [FIRStorageUtils defaultRequestForPath:path]; + XCTAssertEqualObjects([request.URL absoluteString], + @"https://firebasestorage.googleapis.com/v0/b/bucket/o"); +} + +- (void)testEncodedURLForFullPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:@"path/to/object"]; + NSString *encodedURL = [FIRStorageUtils encodedURLForPath:path]; + XCTAssertEqualObjects(encodedURL, @"/v0/b/bucket/o/path%2Fto%2Fobject"); +} + +- (void)testEncodedURLForNoPath { + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:@"bucket" object:nil]; + NSString *encodedURL = [FIRStorageUtils encodedURLForPath:path]; + XCTAssertEqualObjects(encodedURL, @"/v0/b/bucket/o"); +} + +@end |