From 6e8475f9bcb2ffcbf1f01b90b819bf2b54c1f372 Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 6 Oct 2022 13:43:17 -0700 Subject: [PATCH 1/5] Create GIDEMMSupportTest.m --- GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m | 210 ++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m diff --git a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m new file mode 100644 index 00000000..fb8f9d08 --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m @@ -0,0 +1,210 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import + +#import "GoogleSignIn/Sources/GIDEMMSupport.h" + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" + +#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" +#import "GoogleSignIn/Sources/GIDMDMPasscodeState.h" + +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GoogleUtilities_MethodSwizzler; +@import GoogleUtilities_SwizzlerTestHelpers; +@import OCMock; +#else +#import +#import +#import +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +// The system name in old iOS versions. +static NSString *const kOldIOSName = @"iPhone OS"; + +// The system name in new iOS versions. +static NSString *const kNewIOSName = @"iOS"; + +@interface GIDEMMSupportTest : XCTestCase +@end + +@implementation GIDEMMSupportTest + +- (void)testUpdatedEMMParametersWithParameters_NoEMM { + NSDictionary *originalParameters = @{ + @"xyz" : @"xyz", + }; + + NSDictionary *updatedEMMParameters = + [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; + + XCTAssertEqualObjects(updatedEMMParameters, originalParameters); +} + +- (void)testUpdateEMMParametersWithParameters_systemName { + [GULSwizzler swizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO + withBlock:^(id sender) { return kNewIOSName; }]; + + NSDictionary *originalParameters = @{ + @"emm_support" : @"xyz", + }; + + NSDictionary *updatedEMMParameters = + [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; + + NSDictionary *expectedParameters = @{ + @"emm_support" : @"xyz", + @"device_os" : [NSString stringWithFormat:@"%@ %@", + kNewIOSName, [UIDevice currentDevice].systemVersion] + }; + + XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); + + + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; +} + +// When the systemName is @"iPhone OS" we still get "iOS". +- (void)testUpdateEMMParametersWithParameters_systemNameNormalization { + [GULSwizzler swizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO + withBlock:^(id sender) { return kOldIOSName; }]; + + NSDictionary *originalParameters = @{ + @"emm_support" : @"xyz", + }; + + NSDictionary *updatedEMMParameters = + [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; + + NSDictionary *expectedParameters = @{ + @"emm_support" : @"xyz", + @"device_os" : [NSString stringWithFormat:@"%@ %@", + kNewIOSName, [UIDevice currentDevice].systemVersion] + }; + + XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); + + + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; +} + +- (void)testUpdateEMMParametersWithParameters_passcodInfo { + [GULSwizzler swizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO + withBlock:^(id sender) { return kOldIOSName; }]; + + NSDictionary *originalParameters = @{ + @"emm_support" : @"xyz", + @"device_os" : @"old one", + @"emm_passcode_info" : @"something", + }; + + NSDictionary *updatedEMMParameters = + [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; + + NSDictionary *expectedParameters = @{ + @"emm_support" : @"xyz", + @"device_os" : [NSString stringWithFormat:@"%@ %@", + kNewIOSName, [UIDevice currentDevice].systemVersion], + @"emm_passcode_info" : [GIDMDMPasscodeState passcodeState].info, + }; + + XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); + + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; +} + +- (void)testHandleTokenFetchEMMError_errorIsEMM { + // Set expectations. + NSDictionary *errorJSON = @{ @"error" : @"EMM Specific Error" }; + NSError *emmError = [NSError errorWithDomain:@"anydomain" + code:12345 + userInfo:@{ OIDOAuthErrorResponseErrorKey : errorJSON }]; + id mockEMMErrorHandler = OCMStrictClassMock([GIDEMMErrorHandler class]); + [[[mockEMMErrorHandler stub] andReturn:mockEMMErrorHandler] sharedInstance]; + __block void (^savedCompletion)(void); + [[[mockEMMErrorHandler expect] andReturnValue:@YES] + handleErrorFromResponse:errorJSON completion:[OCMArg checkWithBlock:^(id arg) { + savedCompletion = arg; + return YES; + }]]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Callback is called"]; + + [GIDEMMSupport handleTokenFetchEMMError:emmError completion:^(NSError *error) { + [expectation fulfill]; + XCTAssertEqualObjects(error.domain, kGIDSignInErrorDomain); + XCTAssertEqual(error.code, kGIDSignInErrorCodeEMM); + }]; + + savedCompletion(); + [self waitForExpectationsWithTimeout:3 handler:nil]; + [mockEMMErrorHandler verify]; + [mockEMMErrorHandler stopMocking]; +} + +- (void)testHandleTokenFetchEMMError_errorIsNotEMM { + // Set expectations. + NSDictionary *errorJSON = @{ @"error" : @"Not EMM Specific Error" }; + NSError *emmError = [NSError errorWithDomain:@"anydomain" + code:12345 + userInfo:@{ OIDOAuthErrorResponseErrorKey : errorJSON }]; + id mockEMMErrorHandler = OCMStrictClassMock([GIDEMMErrorHandler class]); + [[[mockEMMErrorHandler stub] andReturn:mockEMMErrorHandler] sharedInstance]; + __block void (^savedCompletion)(void); + [[[mockEMMErrorHandler expect] andReturnValue:@NO] + handleErrorFromResponse:errorJSON completion:[OCMArg checkWithBlock:^(id arg) { + savedCompletion = arg; + return YES; + }]]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Callback is called"]; + + [GIDEMMSupport handleTokenFetchEMMError:emmError completion:^(NSError *error) { + [expectation fulfill]; + XCTAssertEqualObjects(error.domain, @"anydomain"); + XCTAssertEqual(error.code, 12345); + }]; + + savedCompletion(); + [self waitForExpectationsWithTimeout:3 handler:nil]; + [mockEMMErrorHandler verify]; + [mockEMMErrorHandler stopMocking]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST From 111ee27bd707edbdf626e5f57dfcbab24ceab581 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 7 Oct 2022 13:38:55 -0700 Subject: [PATCH 2/5] Resolve comments. --- GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m | 64 +++++++++++---------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m index fb8f9d08..8b083b3e 100644 --- a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m +++ b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m @@ -1,16 +1,18 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #import @@ -74,10 +76,10 @@ - (void)testUpdateEMMParametersWithParameters_systemName { NSDictionary *updatedEMMParameters = [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; + NSString *systemVersion = [UIDevice currentDevice].systemVersion; NSDictionary *expectedParameters = @{ @"emm_support" : @"xyz", - @"device_os" : [NSString stringWithFormat:@"%@ %@", - kNewIOSName, [UIDevice currentDevice].systemVersion] + @"device_os" : [NSString stringWithFormat:@"%@ %@", kNewIOSName, systemVersion] }; XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); @@ -154,24 +156,26 @@ - (void)testHandleTokenFetchEMMError_errorIsEMM { id mockEMMErrorHandler = OCMStrictClassMock([GIDEMMErrorHandler class]); [[[mockEMMErrorHandler stub] andReturn:mockEMMErrorHandler] sharedInstance]; __block void (^savedCompletion)(void); - [[[mockEMMErrorHandler expect] andReturnValue:@YES] + [[[mockEMMErrorHandler stub] andReturnValue:@YES] handleErrorFromResponse:errorJSON completion:[OCMArg checkWithBlock:^(id arg) { savedCompletion = arg; return YES; }]]; - XCTestExpectation *expectation = [self expectationWithDescription:@"Callback is called"]; + XCTestExpectation *notCalled = [self expectationWithDescription:@"Callback is not called"]; + notCalled.inverted = YES; + XCTestExpectation *called = [self expectationWithDescription:@"Callback is called"]; [GIDEMMSupport handleTokenFetchEMMError:emmError completion:^(NSError *error) { - [expectation fulfill]; + [notCalled fulfill]; + [called fulfill]; XCTAssertEqualObjects(error.domain, kGIDSignInErrorDomain); XCTAssertEqual(error.code, kGIDSignInErrorCodeEMM); }]; - + + [self waitForExpectations:@[ notCalled ] timeout:1]; savedCompletion(); - [self waitForExpectationsWithTimeout:3 handler:nil]; - [mockEMMErrorHandler verify]; - [mockEMMErrorHandler stopMocking]; + [self waitForExpectations:@[ called ] timeout:1]; } - (void)testHandleTokenFetchEMMError_errorIsNotEMM { @@ -183,24 +187,26 @@ - (void)testHandleTokenFetchEMMError_errorIsNotEMM { id mockEMMErrorHandler = OCMStrictClassMock([GIDEMMErrorHandler class]); [[[mockEMMErrorHandler stub] andReturn:mockEMMErrorHandler] sharedInstance]; __block void (^savedCompletion)(void); - [[[mockEMMErrorHandler expect] andReturnValue:@NO] + [[[mockEMMErrorHandler stub] andReturnValue:@NO] handleErrorFromResponse:errorJSON completion:[OCMArg checkWithBlock:^(id arg) { savedCompletion = arg; return YES; }]]; - XCTestExpectation *expectation = [self expectationWithDescription:@"Callback is called"]; - + XCTestExpectation *notCalled = [self expectationWithDescription:@"Callback is not called"]; + notCalled.inverted = YES; + XCTestExpectation *called = [self expectationWithDescription:@"Callback is called"]; + [GIDEMMSupport handleTokenFetchEMMError:emmError completion:^(NSError *error) { - [expectation fulfill]; + [notCalled fulfill]; + [called fulfill]; XCTAssertEqualObjects(error.domain, @"anydomain"); XCTAssertEqual(error.code, 12345); }]; + [self waitForExpectations:@[ notCalled ] timeout:1]; savedCompletion(); - [self waitForExpectationsWithTimeout:3 handler:nil]; - [mockEMMErrorHandler verify]; - [mockEMMErrorHandler stopMocking]; + [self waitForExpectations:@[ called ] timeout:1]; } @end From ff62ad71851c9487ae9f536e7de6b773738a28a7 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 7 Oct 2022 17:13:25 -0700 Subject: [PATCH 3/5] Resolve comments --- GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m | 42 ++++++++++++--------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m index 8b083b3e..90cabcad 100644 --- a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m +++ b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m @@ -47,14 +47,19 @@ // The system name in new iOS versions. static NSString *const kNewIOSName = @"iOS"; +// They keys in EMM dictionary. +static NSString *const kEMMKey = @"emm_support"; +static NSString *const kDeviceOSKey = @"device_os"; +static NSString *const kEMMPasscodeInfoKey = @"emm_passcode_info"; + @interface GIDEMMSupportTest : XCTestCase @end @implementation GIDEMMSupportTest -- (void)testUpdatedEMMParametersWithParameters_NoEMM { +- (void)testUpdatedEMMParametersWithParameters_NoEMMKey { NSDictionary *originalParameters = @{ - @"xyz" : @"xyz", + @"not_emm_support_key" : @"xyz", }; NSDictionary *updatedEMMParameters = @@ -70,7 +75,7 @@ - (void)testUpdateEMMParametersWithParameters_systemName { withBlock:^(id sender) { return kNewIOSName; }]; NSDictionary *originalParameters = @{ - @"emm_support" : @"xyz", + kEMMKey : @"xyz", }; NSDictionary *updatedEMMParameters = @@ -78,16 +83,17 @@ - (void)testUpdateEMMParametersWithParameters_systemName { NSString *systemVersion = [UIDevice currentDevice].systemVersion; NSDictionary *expectedParameters = @{ - @"emm_support" : @"xyz", - @"device_os" : [NSString stringWithFormat:@"%@ %@", kNewIOSName, systemVersion] + kEMMKey : @"xyz", + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, systemVersion] }; XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); - - [GULSwizzler unswizzleClass:[UIDevice class] - selector:@selector(systemName) - isClassSelector:NO]; + [self addTeardownBlock:^{ + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; + }]; } // When the systemName is @"iPhone OS" we still get "iOS". @@ -98,15 +104,15 @@ - (void)testUpdateEMMParametersWithParameters_systemNameNormalization { withBlock:^(id sender) { return kOldIOSName; }]; NSDictionary *originalParameters = @{ - @"emm_support" : @"xyz", + kEMMKey : @"xyz", }; NSDictionary *updatedEMMParameters = [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; NSDictionary *expectedParameters = @{ - @"emm_support" : @"xyz", - @"device_os" : [NSString stringWithFormat:@"%@ %@", + kEMMKey : @"xyz", + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, [UIDevice currentDevice].systemVersion] }; @@ -125,19 +131,19 @@ - (void)testUpdateEMMParametersWithParameters_passcodInfo { withBlock:^(id sender) { return kOldIOSName; }]; NSDictionary *originalParameters = @{ - @"emm_support" : @"xyz", - @"device_os" : @"old one", - @"emm_passcode_info" : @"something", + kEMMKey : @"xyz", + kDeviceOSKey : @"old one", + kEMMPasscodeInfoKey : @"something", }; NSDictionary *updatedEMMParameters = [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; NSDictionary *expectedParameters = @{ - @"emm_support" : @"xyz", - @"device_os" : [NSString stringWithFormat:@"%@ %@", + kEMMKey : @"xyz", + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, [UIDevice currentDevice].systemVersion], - @"emm_passcode_info" : [GIDMDMPasscodeState passcodeState].info, + kEMMPasscodeInfoKey : [GIDMDMPasscodeState passcodeState].info, }; XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); From eb4ce434de78057276370029543f200e94180705 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 10 Oct 2022 13:47:32 -0700 Subject: [PATCH 4/5] Minor improvement --- GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m index 90cabcad..8ed52778 100644 --- a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m +++ b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m @@ -81,10 +81,9 @@ - (void)testUpdateEMMParametersWithParameters_systemName { NSDictionary *updatedEMMParameters = [GIDEMMSupport updatedEMMParametersWithParameters:originalParameters]; - NSString *systemVersion = [UIDevice currentDevice].systemVersion; NSDictionary *expectedParameters = @{ kEMMKey : @"xyz", - kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, systemVersion] + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, [self systemVersion]] }; XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); @@ -112,8 +111,7 @@ - (void)testUpdateEMMParametersWithParameters_systemNameNormalization { NSDictionary *expectedParameters = @{ kEMMKey : @"xyz", - kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", - kNewIOSName, [UIDevice currentDevice].systemVersion] + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, [self systemVersion]] }; XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); @@ -141,8 +139,7 @@ - (void)testUpdateEMMParametersWithParameters_passcodInfo { NSDictionary *expectedParameters = @{ kEMMKey : @"xyz", - kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", - kNewIOSName, [UIDevice currentDevice].systemVersion], + kDeviceOSKey : [NSString stringWithFormat:@"%@ %@", kNewIOSName, [self systemVersion]], kEMMPasscodeInfoKey : [GIDMDMPasscodeState passcodeState].info, }; @@ -215,6 +212,12 @@ - (void)testHandleTokenFetchEMMError_errorIsNotEMM { [self waitForExpectations:@[ called ] timeout:1]; } +# pragma mark - Helpers + +- (NSString *)systemVersion { + return [UIDevice currentDevice].systemVersion; +} + @end NS_ASSUME_NONNULL_END From 6a84c987fa83012f2bad96d0e9aee1a4affe5ae0 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 10 Oct 2022 13:51:11 -0700 Subject: [PATCH 5/5] Move unswizzle into `addTeardownBlock:` --- GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m index 8ed52778..aaf5c71e 100644 --- a/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m +++ b/GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m @@ -116,10 +116,11 @@ - (void)testUpdateEMMParametersWithParameters_systemNameNormalization { XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); - - [GULSwizzler unswizzleClass:[UIDevice class] - selector:@selector(systemName) - isClassSelector:NO]; + [self addTeardownBlock:^{ + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; + }]; } - (void)testUpdateEMMParametersWithParameters_passcodInfo { @@ -145,9 +146,12 @@ - (void)testUpdateEMMParametersWithParameters_passcodInfo { XCTAssertEqualObjects(updatedEMMParameters, expectedParameters); - [GULSwizzler unswizzleClass:[UIDevice class] - selector:@selector(systemName) - isClassSelector:NO]; + [self addTeardownBlock:^{ + [GULSwizzler unswizzleClass:[UIDevice class] + selector:@selector(systemName) + isClassSelector:NO]; + }]; + } - (void)testHandleTokenFetchEMMError_errorIsEMM {