diff --git a/CHANGELOG.md b/CHANGELOG.md index 6364a588..5f348c49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,15 @@ | tvOS | **13.0** | | macOS | **10.15** | | watchOS | 7.0 | +- Remove dependency on `FBLPromises`. The following public API have + been removed: + - `- [NSURLSession gul_dataTaskPromiseWithRequest:]` + - `GULURLSessionDataResponse` + The following promise-based public API have been replaced with + completion handler-based alternatives. + - `- [GULKeychainStorage getObjectForKey:objectClass:accessGroup:]` + - `- [GULKeychainStorage setObject:forKey:accessGroup:]` + - `- [GULKeychainStorage removeObjectForKey:accessGroup:]` # 7.13.3 - Rename parameter placeholder in `GULSecureCoding` unarchiving API to avoid diff --git a/GoogleUtilities.podspec b/GoogleUtilities.podspec index 31387bca..7cf96549 100644 --- a/GoogleUtilities.podspec +++ b/GoogleUtilities.podspec @@ -47,7 +47,6 @@ other Google CocoaPods. They're not intended for direct public usage. 'third_party/IsAppEncrypted/**/*.[mh]' ] es.public_header_files = 'GoogleUtilities/Environment/Public/GoogleUtilities/*.h' - es.dependency 'PromisesObjC', '>= 1.2', '< 3.0' es.dependency 'GoogleUtilities/Privacy' es.frameworks = [ 'Security' diff --git a/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h b/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h index af10cb4d..eb90ea34 100644 --- a/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h +++ b/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h @@ -16,8 +16,6 @@ #import -@class FBLPromise; - NS_ASSUME_NONNULL_BEGIN /// The class provides a convenient, multiplatform abstraction of the Keychain. @@ -34,42 +32,46 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithService:(NSString *)service; -/** - * Get an object by key. - * @param key The key. - * @param objectClass The expected object class required by `NSSecureCoding`. - * @param accessGroup The Keychain Access Group. - * - * @return Returns a promise. It is resolved with an object stored by key if exists. It is resolved - * with `nil` when the object not found. It fails on a Keychain error. - */ -- (FBLPromise> *)getObjectForKey:(NSString *)key - objectClass:(Class)objectClass - accessGroup:(nullable NSString *)accessGroup; +/// Get an object by key. +/// @param key The key. +/// @param objectClass The expected object class required by `NSSecureCoding`. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain read is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object stored in +/// the keychain, or `nil` if it does not exist, is passed to the completion +/// handler. +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; -/** - * Saves the given object by the given key. - * @param object The object to store. - * @param key The key to store the object. If there is an existing object by the key, it will be - * overridden. - * @param accessGroup The Keychain Access Group. - * - * @return Returns which is resolved with `[NSNull null]` on success. - */ -- (FBLPromise *)setObject:(id)object - forKey:(NSString *)key - accessGroup:(nullable NSString *)accessGroup; +/// Saves the given object by the given key. +/// @param object The object to store. +/// @param key The key to store the object. If there is an existing object by the key, it will be +/// overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain write is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object written to +/// the keychain is passed to the completion handler. +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; -/** - * Removes the object by the given key. - * @param key The key to store the object. If there is an existing object by the key, it will be - * overridden. - * @param accessGroup The Keychain Access Group. - * - * @return Returns which is resolved with `[NSNull null]` on success. - */ -- (FBLPromise *)removeObjectForKey:(NSString *)key - accessGroup:(nullable NSString *)accessGroup; +/// Removes the object by the given key. +/// @param key The key to store the object. If there is an existing object by +/// the key, it will be overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain removal is complete. An error is passed to the +/// completion handler if the keychain removal fails. +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler; #if TARGET_OS_OSX /// If not `nil`, then only this keychain will be used to save and read data (see diff --git a/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h b/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h deleted file mode 100644 index e88eb67b..00000000 --- a/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2020 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 - -NS_ASSUME_NONNULL_BEGIN - -/** The class represents HTTP response received from `NSURLSession`. */ -@interface GULURLSessionDataResponse : NSObject - -@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; -@property(nonatomic, nullable, readonly) NSData *HTTPBody; - -- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(nullable NSData *)body; - -@end - -NS_ASSUME_NONNULL_END diff --git a/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h b/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h deleted file mode 100644 index 7bed005e..00000000 --- a/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2020 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 - -@class FBLPromise; -@class GULURLSessionDataResponse; - -NS_ASSUME_NONNULL_BEGIN - -/** Promise based API for `NSURLSession`. */ -@interface NSURLSession (GULPromises) - -/** Creates a promise wrapping `-[NSURLSession dataTaskWithRequest:completionHandler:]` method. - * @param URLRequest The request to create a data task with. - * @return A promise that is fulfilled when an HTTP response is received (with any response code), - * or is rejected with the error passed to the task completion. - */ -- (FBLPromise *)gul_dataTaskPromiseWithRequest: - (NSURLRequest *)URLRequest; - -@end - -NS_ASSUME_NONNULL_END diff --git a/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m index 2b5cc8a3..e6aa69a7 100644 --- a/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m +++ b/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m @@ -17,12 +17,6 @@ #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" #import -#if __has_include() -#import -#else -#import "FBLPromises.h" -#endif - #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" @interface GULKeychainStorage () @@ -56,110 +50,113 @@ - (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache { #pragma mark - Public -- (FBLPromise> *)getObjectForKey:(NSString *)key - objectClass:(Class)objectClass - accessGroup:(nullable NSString *)accessGroup { - return [FBLPromise onQueue:self.inMemoryCacheQueue - do:^id _Nullable { - // Return cached object or fail otherwise. - id object = [self.inMemoryCache objectForKey:key]; - return object - ?: [[NSError alloc] - initWithDomain:FBLPromiseErrorDomain - code:FBLPromiseErrorCodeValidationFailure - userInfo:nil]; - }] - .recover(^id _Nullable(NSError *error) { - // Look for the object in the keychain. - return [self getObjectFromKeychainForKey:key - objectClass:objectClass - accessGroup:accessGroup]; - }); +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Return cached object or fail otherwise. + id object = [self.inMemoryCache objectForKey:key]; + if (object) { + completionHandler(object, nil); + } else { + // Look for the object in the keychain. + [self getObjectFromKeychainForKey:key + objectClass:objectClass + accessGroup:accessGroup + completionHandler:completionHandler]; + } + }); } -- (FBLPromise *)setObject:(id)object - forKey:(NSString *)key - accessGroup:(nullable NSString *)accessGroup { - return [FBLPromise onQueue:self.inMemoryCacheQueue - do:^id _Nullable { - // Save to the in-memory cache first. - [self.inMemoryCache setObject:object forKey:[key copy]]; - return [NSNull null]; - }] - .thenOn(self.keychainQueue, ^id(id result) { - // Then store the object to the keychain. - NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; - NSError *error; - NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object - requiringSecureCoding:YES - error:&error]; - if (!encodedObject) { - return error; - } - - if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { - return error; - } - - return [NSNull null]; - }); +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save to the in-memory cache first. + [self.inMemoryCache setObject:object forKey:[key copy]]; + + dispatch_async(self.keychainQueue, ^{ + // Then store the object to the keychain. + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object + requiringSecureCoding:YES + error:&error]; + if (!encodedObject) { + completionHandler(nil, error); + return; + } + + if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { + completionHandler(nil, error); + return; + } + + completionHandler(object, nil); + }); + }); } -- (FBLPromise *)removeObjectForKey:(NSString *)key - accessGroup:(nullable NSString *)accessGroup { - return [FBLPromise onQueue:self.inMemoryCacheQueue - do:^id _Nullable { - [self.inMemoryCache removeObjectForKey:key]; - return nil; - }] - .thenOn(self.keychainQueue, ^id(id result) { - NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; - - NSError *error; - if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { - return error; - } - - return [NSNull null]; - }); +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + [self.inMemoryCache removeObjectForKey:key]; + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + + NSError *error; + if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { + completionHandler(error); + } else { + completionHandler(nil); + } + }); + }); } #pragma mark - Private -- (FBLPromise> *)getObjectFromKeychainForKey:(NSString *)key - objectClass:(Class)objectClass - accessGroup:(nullable NSString *)accessGroup { +- (void)getObjectFromKeychainForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(id _Nullable obj, + NSError *_Nullable error))completionHandler { // Look for the object in the keychain. - return [FBLPromise - onQueue:self.keychainQueue - do:^id { - NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; - NSError *error; - NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; - - if (error) { - return error; - } - if (!encodedObject) { - return nil; - } - id object = [NSKeyedUnarchiver unarchivedObjectOfClass:objectClass - fromData:encodedObject - error:&error]; - if (error) { - return error; - } - - return object; - }] - .thenOn(self.inMemoryCacheQueue, - ^id _Nullable(id _Nullable object) { - // Save object to the in-memory cache if exists and return the object. - if (object) { - [self.inMemoryCache setObject:object forKey:[key copy]]; - } - return object; - }); + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; + + if (error) { + completionHandler(nil, error); + return; + } + if (!encodedObject) { + completionHandler(nil, nil); + return; + } + id object = [NSKeyedUnarchiver unarchivedObjectOfClass:objectClass + fromData:encodedObject + error:&error]; + if (error) { + completionHandler(nil, error); + return; + } + + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save object to the in-memory cache if exists and return the object. + if (object) { + [self.inMemoryCache setObject:object forKey:[key copy]]; + } + + completionHandler(object, nil); + }); + }); } - (void)resetInMemoryCache { diff --git a/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m b/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m deleted file mode 100644 index 559875a7..00000000 --- a/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" - -@implementation GULURLSessionDataResponse - -- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(NSData *)body { - self = [super init]; - if (self) { - _HTTPResponse = response; - _HTTPBody = body; - } - return self; -} - -@end diff --git a/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m b/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m deleted file mode 100644 index 6c70310f..00000000 --- a/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2020 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 "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h" - -#if __has_include() -#import -#else -#import "FBLPromises.h" -#endif - -#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" - -@implementation NSURLSession (GULPromises) - -- (FBLPromise *)gul_dataTaskPromiseWithRequest: - (NSURLRequest *)URLRequest { - return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { - [[self dataTaskWithRequest:URLRequest - completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, - NSError *_Nullable error) { - if (error) { - reject(error); - } else { - fulfill([[GULURLSessionDataResponse alloc] - initWithResponse:(NSHTTPURLResponse *)response - HTTPBody:data]); - } - }] resume]; - }]; -} - -@end diff --git a/GoogleUtilities/Tests/Unit/Environment/GULKeychainStorageTests.m b/GoogleUtilities/Tests/Unit/Environment/GULKeychainStorageTests.m index d2512974..12160c6b 100644 --- a/GoogleUtilities/Tests/Unit/Environment/GULKeychainStorageTests.m +++ b/GoogleUtilities/Tests/Unit/Environment/GULKeychainStorageTests.m @@ -29,7 +29,6 @@ #import #import -#import "FBLPromise+Testing.h" #import "GoogleUtilities/Tests/Unit/Utils/GULTestKeychain.h" #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" @@ -120,16 +119,21 @@ - (void)testGetExistingObjectClassMismatch { // Skip in-memory cache because the error is relevant only for Keychain. OCMExpect([self.mockCache objectForKey:key]).andReturn(nil); - FBLPromise> *getPromise = [self.storage getObjectForKey:key - objectClass:[NSString class] - accessGroup:nil]; - - XCTAssert(FBLWaitForPromisesWithTimeout(1)); - XCTAssertNil(getPromise.value); - XCTAssertNotNil(getPromise.error); - // TODO: Test for particular error. - - OCMVerifyAll(self.mockCache); + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self.storage getObjectForKey:key + objectClass:[NSString class] + accessGroup:nil + completionHandler:^(id _Nullable obj, NSError *_Nullable error) { + XCTAssertNil(obj); + // Assert class mismatch error. + XCTAssertNotNil(error); + XCTAssertEqual(error.domain, NSCocoaErrorDomain); + XCTAssertEqual(error.code, 4864); + + OCMVerifyAll(self.mockCache); + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:1.0]; } - (void)testRemoveExistingObject { @@ -155,15 +159,23 @@ - (void)testRemoveNonExistingObject { - (void)assertSuccessWriteObject:(id)object forKey:(NSString *)key { OCMExpect([self.mockCache setObject:object forKey:key]).andForwardToRealObject(); - FBLPromise *setPromise = [self.storage setObject:object forKey:key accessGroup:nil]; - - XCTAssert(FBLWaitForPromisesWithTimeout(1)); - XCTAssertNil(setPromise.error, @"%@", self.name); - + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + __weak __auto_type weakSelf = self; + [self.storage setObject:object + forKey:key + accessGroup:nil + completionHandler:^(id _Nullable obj, NSError *_Nullable error) { + if (!weakSelf) { + return; + } + XCTAssertNil(error, @"%@", weakSelf.name); + // Check in-memory cache. + XCTAssertEqualObjects([weakSelf.cache objectForKey:key], object); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:1.0]; OCMVerifyAll(self.mockCache); - - // Check in-memory cache. - XCTAssertEqualObjects([self.cache objectForKey:key], object); } - (void)assertSuccessReadObject:(id)object @@ -176,39 +188,57 @@ - (void)assertSuccessReadObject:(id)object OCMExpect([self.mockCache setObject:object forKey:key]).andForwardToRealObject(); } - FBLPromise> *getPromise = - [self.storage getObjectForKey:key objectClass:class accessGroup:nil]; - - XCTAssert(FBLWaitForPromisesWithTimeout(1), @"%@", self.name); - XCTAssertEqualObjects(getPromise.value, object, @"%@", self.name); - XCTAssertNil(getPromise.error, @"%@", self.name); - + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + __weak __auto_type weakSelf = self; + [self.storage + getObjectForKey:key + objectClass:class + accessGroup:nil + completionHandler:^(id _Nullable obj, NSError *_Nullable error) { + if (!weakSelf) { + return; + } + XCTAssertEqualObjects(obj, object, @"%@", weakSelf.name); + XCTAssertNil(error, @"%@", weakSelf.name); + // Check in-memory cache. + XCTAssertEqualObjects([weakSelf.cache objectForKey:key], object, @"%@", weakSelf.name); + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:1.0]; OCMVerifyAll(self.mockCache); - - // Check in-memory cache. - XCTAssertEqualObjects([self.cache objectForKey:key], object, @"%@", self.name); } - (void)assertNonExistingObjectForKey:(NSString *)key class:(Class)class { OCMExpect([self.mockCache objectForKey:key]).andForwardToRealObject(); - FBLPromise> *promise = - [self.storage getObjectForKey:key objectClass:class accessGroup:nil]; - - XCTAssert(FBLWaitForPromisesWithTimeout(1)); - XCTAssertNil(promise.error, @"%@", self.name); - XCTAssertNil(promise.value, @"%@", self.name); - + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + __weak __auto_type weakSelf = self; + [self.storage getObjectForKey:key + objectClass:class + accessGroup:nil + completionHandler:^(id _Nullable obj, NSError *_Nullable error) { + if (!weakSelf) { + return; + } + XCTAssertNil(error, @"%@", weakSelf.name); + XCTAssertNil(obj, @"%@", weakSelf.name); + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:1.0]; OCMVerifyAll(self.mockCache); } - (void)assertRemoveObjectForKey:(NSString *)key { OCMExpect([self.mockCache removeObjectForKey:key]).andForwardToRealObject(); - FBLPromise *removePromise = [self.storage removeObjectForKey:key accessGroup:nil]; - XCTAssert(FBLWaitForPromisesWithTimeout(1)); - XCTAssertNil(removePromise.error); - + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + [self.storage removeObjectForKey:key + accessGroup:nil + completionHandler:^(NSError *_Nullable error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:1.0]; OCMVerifyAll(self.mockCache); } diff --git a/GoogleUtilities/Tests/Unit/Environment/NSURLSession+GULPromisesTests.m b/GoogleUtilities/Tests/Unit/Environment/NSURLSession+GULPromisesTests.m deleted file mode 100644 index 5a4994bc..00000000 --- a/GoogleUtilities/Tests/Unit/Environment/NSURLSession+GULPromisesTests.m +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2020 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 - -#import -#import "FBLPromise+Testing.h" -#import "GoogleUtilities/Tests/Unit/Shared/URLSession/FIRURLSessionOCMockStub.h" - -#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" -#import "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h" - -#if !TARGET_OS_MACCATALYST - -@interface NSURLSession_GULPromisesTests : XCTestCase -@property(nonatomic) NSURLSession *URLSession; -@property(nonatomic) id URLSessionMock; -@end - -@implementation NSURLSession_GULPromisesTests - -- (void)setUp { - self.URLSession = [NSURLSession - sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - self.URLSessionMock = OCMPartialMock(self.URLSession); -} - -- (void)tearDown { - [self.URLSessionMock stopMocking]; - self.URLSessionMock = nil; - self.URLSession = nil; -} - -- (void)testDataTaskPromiseWithRequestSuccess { - NSURL *url = [NSURL URLWithString:@"https://localhost"]; - NSURLRequest *request = [NSURLRequest requestWithURL:url]; - - NSHTTPURLResponse *expectedResponse = [[NSHTTPURLResponse alloc] initWithURL:url - statusCode:200 - HTTPVersion:@"1.1" - headerFields:nil]; - NSData *expectedBody = [@"body" dataUsingEncoding:NSUTF8StringEncoding]; - - [FIRURLSessionOCMockStub - stubURLSessionDataTaskWithResponse:expectedResponse - body:expectedBody - error:nil - URLSessionMock:self.URLSessionMock - requestValidationBlock:^BOOL(NSURLRequest *_Nonnull sentRequest) { - return [sentRequest isEqual:request]; - }]; - - __auto_type taskPromise = [self.URLSessionMock gul_dataTaskPromiseWithRequest:request]; - - XCTAssert(FBLWaitForPromisesWithTimeout(1.0)); - - XCTAssertTrue(taskPromise.isFulfilled); - XCTAssertNil(taskPromise.error); - XCTAssertEqualObjects(taskPromise.value.HTTPResponse, expectedResponse); - XCTAssertEqualObjects(taskPromise.value.HTTPBody, expectedBody); -} - -- (void)testDataTaskPromiseWithRequestError { - NSURL *url = [NSURL URLWithString:@"https://localhost"]; - NSURLRequest *request = [NSURLRequest requestWithURL:url]; - - NSError *expectedError = [NSError errorWithDomain:@"testDataTaskPromiseWithRequestError" - code:-1 - userInfo:nil]; - - [FIRURLSessionOCMockStub - stubURLSessionDataTaskWithResponse:nil - body:nil - error:expectedError - URLSessionMock:self.URLSessionMock - requestValidationBlock:^BOOL(NSURLRequest *_Nonnull sentRequest) { - return [sentRequest isEqual:request]; - }]; - - __auto_type taskPromise = [self.URLSessionMock gul_dataTaskPromiseWithRequest:request]; - - XCTAssert(FBLWaitForPromisesWithTimeout(0.5)); - - XCTAssertTrue(taskPromise.isRejected); - XCTAssertEqualObjects(taskPromise.error, expectedError); - XCTAssertNil(taskPromise.value); -} - -@end - -#endif // !TARGET_OS_MACCATALYST diff --git a/Package.swift b/Package.swift index 85868c39..729a15ff 100644 --- a/Package.swift +++ b/Package.swift @@ -88,7 +88,6 @@ let package = Package( .target( name: "GoogleUtilities-Environment", dependencies: [ - .product(name: "FBLPromises", package: "Promises"), "third-party-IsAppEncrypted", ], path: "GoogleUtilities/Environment",