From 24690446aaa2190169014e4d49546a745935c94c Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Fri, 4 Aug 2017 16:19:19 -0700 Subject: [PATCH 01/55] Work in progress --- .../MobileCenterDistribute/MSDistribute.m | 63 +++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index 1156d167ad..329c69fe9c 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -220,13 +220,25 @@ - (void)requestUpdateToken:(NSString *)releaseHash { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" Class clazz = [SFSafariViewController class]; -#pragma clang diagnostic pop if (clazz) { - // Manipulate App UI on the main queue. - dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInEmbeddedSafari:url fromClass:clazz]; - }); + // iOS 11 + Class authClazz = [SFAuthenticationSession class]; + if(authClazz) { + + // Manipulate App UI on the main queue. +// dispatch_async(dispatch_get_main_queue(), ^{ + [self openURLInAuthenticationSessionWith:url fromClass:authClazz]; +// }); + } else { + // iOS 9 and 10 + + // Manipulate App UI on the main queue. + dispatch_async(dispatch_get_main_queue(), ^{ + [self openURLInEmbeddedSafari:url fromClass:clazz]; + }); + } +#pragma clang diagnostic pop } else { // iOS 8.x. @@ -435,6 +447,33 @@ - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret rele return components.URL; } +- (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { + MSLogDebug([MSDistribute logTag], @"Using SFAuthenticationSession to open URL: %@", url); + + NSString *callbackUrlScheme = [NSString stringWithFormat:kMSDefaultCustomSchemeFormat, self.appSecret]; + + if (@available(iOS 11.0, *)) { + SFAuthenticationSession *authenticationSession = [[clazz alloc] initWithURL:url callbackURLScheme:callbackUrlScheme completionHandler:^(NSURL *callbackUrl, NSError *error) { + MSLogDebug([MSDistribute logTag], @"Called %@ with errror: %@", callbackUrl, error.localizedDescription); + + if(error.code == SFAuthenticationErrorCanceledLogin) { + MSLogError([MSDistribute logTag], @"Authentication session was cancelled by user or failed."); + } + + if(callbackUrl) { + [self openURL:callbackUrl]; + } + }]; + BOOL success = [authenticationSession start]; + if(success) { + MSLogDebug([MSDistribute logTag], @"Authentication Session Started, showing confirmation dialog"); + } + } else { + // Fallback on earlier versions + } +} + +// TODO: rename method - (void)openURLInEmbeddedSafari:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFSafariViewController to open URL: %@", url); @@ -546,12 +585,14 @@ - (BOOL)handleUpdate:(MSReleaseDetails *)details { - (BOOL)checkForUpdatesAllowed { - // Check if we are not in AppStore or TestFlight environments. - BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; - - // Check if a debugger is attached. - BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; - return environmentOkay && noDebuggerAttached; + return YES; + +// // Check if we are not in AppStore or TestFlight environments. +// BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; +// +// // Check if a debugger is attached. +// BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; +// return environmentOkay && noDebuggerAttached; } - (BOOL)isNewerVersion:(MSReleaseDetails *)details { From d190fb5a40431661497845a0ca6d331f159e7f14 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Fri, 11 Aug 2017 19:52:25 -0700 Subject: [PATCH 02/55] Working implementation --- .../MobileCenterDistribute/MSDistribute.m | 13 +++++++++---- .../MobileCenterDistribute/MSDistributePrivate.h | 13 +++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index 329c69fe9c..22c84b33b3 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -40,6 +40,9 @@ @implementation MSDistribute @synthesize channelConfiguration = _channelConfiguration; + + + #pragma mark - Service initialization - (instancetype)init { @@ -453,7 +456,9 @@ - (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { NSString *callbackUrlScheme = [NSString stringWithFormat:kMSDefaultCustomSchemeFormat, self.appSecret]; if (@available(iOS 11.0, *)) { - SFAuthenticationSession *authenticationSession = [[clazz alloc] initWithURL:url callbackURLScheme:callbackUrlScheme completionHandler:^(NSURL *callbackUrl, NSError *error) { + SFAuthenticationSession *session = [[clazz alloc] initWithURL:url callbackURLScheme:callbackUrlScheme completionHandler:^(NSURL *callbackUrl, NSError *error) { + + self.authenticationSession = nil; MSLogDebug([MSDistribute logTag], @"Called %@ with errror: %@", callbackUrl, error.localizedDescription); if(error.code == SFAuthenticationErrorCanceledLogin) { @@ -464,12 +469,12 @@ - (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { [self openURL:callbackUrl]; } }]; - BOOL success = [authenticationSession start]; + self.authenticationSession = session; + + BOOL success = [session start]; if(success) { MSLogDebug([MSDistribute logTag], @"Authentication Session Started, showing confirmation dialog"); } - } else { - // Fallback on earlier versions } } diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h index 6d47c57864..a93307b43c 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h @@ -3,6 +3,12 @@ #import "MSAlertController.h" #import "MSAppDelegate.h" #import "MSDistribute.h" +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" +#import +#pragma clang diagnostic pop +#endif NS_ASSUME_NONNULL_BEGIN @@ -95,6 +101,13 @@ static NSString *const kMSUpdateTokenKey = @"MSUpdateToken"; */ @property(nonatomic) id appDelegate; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" +@property(nullable, nonatomic) SFAuthenticationSession *authenticationSession; +#pragma clang diagnostic pop +#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 + /** * Returns the singleton instance. Meant for testing/demo apps only. * From e3fdb5047e17f52281b8754232d3476016094ff8 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Mon, 28 Aug 2017 15:38:06 -0700 Subject: [PATCH 03/55] App delegate forwarder now handles deprecated APIs * Deprecated APIs are only swizzled if implemented by the original app delegate * New APIs are not swizzled if only their deprecated equivalent is implemented * Refactor swizzling traces --- .../AppDelegate/MSAppDelegateForwarder.m | 95 ++++++++++++++----- .../MSAppDelegateForwarderPrivate.h | 5 + 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 2f316c2d8a..d27d9db3ad 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -17,9 +17,16 @@ static NSString *const kMSReturnedValueSelectorPart = @"returnedValue:"; static NSString *const kMSIsAppDelegateForwarderEnabledKey = @"MobileCenterAppDelegateForwarderEnabled"; +// Original selectors with special handling. +static NSString *const kMSDidReceiveRemoteNotificationFetchHandler = + @"application:didReceiveRemoteNotification:fetchCompletionHandler:"; +static NSString *const kMSOpenURLSourceApplicationAnnotation = @"application:openURL:sourceApplication:annotation:"; +static NSString *const kMSOpenURLOptions = @"application:openURL:options:"; + static NSHashTable> *_delegates = nil; static NSMutableSet *_selectorsToSwizzle = nil; static NSArray *_selectorsNotToOverride = nil; +static NSDictionary *_deprecatedSelectors = nil; static NSMutableDictionary *_originalImplementations = nil; static NSMutableArray *_traceBuffer = nil; static IMP _originalSetDelegateImp = NULL; @@ -79,13 +86,23 @@ + (void)setDelegates:(NSHashTable> *)delegates { + (NSArray *)selectorsNotToOverride { if (!_selectorsNotToOverride) { #if !TARGET_OS_OSX - _selectorsNotToOverride = - @[ NSStringFromSelector(@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)) ]; + _selectorsNotToOverride = @[ kMSDidReceiveRemoteNotificationFetchHandler ]; #endif } return _selectorsNotToOverride; } ++ (NSDictionary *)deprecatedSelectors { + if (!_deprecatedSelectors) { +#if !TARGET_OS_OSX + _deprecatedSelectors = @{kMSOpenURLOptions : kMSOpenURLSourceApplicationAnnotation}; +#else + _deprecatedSelectors = @{}; +#endif + } + return _deprecatedSelectors; +} + + (NSMutableDictionary *)originalImplementations { return _originalImplementations ?: (_originalImplementations = [NSMutableDictionary new]); } @@ -144,8 +161,6 @@ + (void)swizzleOriginalDelegate:(id)originalDelegate { // Swizzle all registered selectors. for (NSString *selectorString in self.selectorsToSwizzle) { - - // The same selector is used on both forwarder and delegate. originalSelector = NSSelectorFromString(selectorString); customSelector = NSSelectorFromString([kMSCustomSelectorPrefix stringByAppendingString:selectorString]); originalImp = @@ -165,11 +180,15 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector originalClass:(Class)originalClass { // Replace original implementation - NSString *originalSelectorString = NSStringFromSelector(originalSelector); + NSString *originalSelectorStr = NSStringFromSelector(originalSelector); Method originalMethod = class_getInstanceMethod(originalClass, originalSelector); IMP customImp = class_getMethodImplementation(self, customSelector); IMP originalImp = NULL; BOOL methodAdded = NO; + BOOL skipped = NO; + NSString *warningMsg; + NSString *remediationMsg = @"You need to explicitly call the Mobile Center API" + @" from your app delegate implementation."; // Replace original implementation by the custom one. if (originalMethod) { @@ -179,17 +198,40 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector * depend on the SDK return value for its own logic so customers already have to call the SDK API * in their implementation which makes swizzling useless. */ - if (![self.selectorsNotToOverride containsObject:originalSelectorString]) { + if (![self.selectorsNotToOverride containsObject:originalSelectorStr]) { originalImp = method_setImplementation(originalMethod, customImp); + } else { + warningMsg = + [NSString stringWithFormat:@"This selector is not supported when already implemented. %@", remediationMsg]; } } else if (![originalClass instancesRespondToSelector:originalSelector]) { - /* - * The original class may not implement the selector (e.g.: optional method from protocol), - * add the method to the original class and associate it with the custom implementation. - */ - Method customMethod = class_getInstanceMethod(self, customSelector); - methodAdded = class_addMethod(originalClass, originalSelector, customImp, method_getTypeEncoding(customMethod)); + // Check for deprecation. + NSString *deprecatedSelectorStr = self.deprecatedSelectors[originalSelectorStr]; + if (deprecatedSelectorStr && + [originalClass instancesRespondToSelector:NSSelectorFromString(deprecatedSelectorStr)]) { + + // An implementation for the deprecated selector exists. Don't add the new method, it might eclipse the original + // implementation. + warningMsg = [NSString + stringWithFormat: + @"No implementation found for this selector, though an implementation of its deprecated API '%@' exists.", + deprecatedSelectorStr]; + } else { + + // Skip this selector if it's deprecated and doesn't have an implementation. + if ([self.deprecatedSelectors.allValues containsObject:originalSelectorStr]) { + skipped = YES; + } else { + + /* + * The original class may not implement the selector (e.g.: optional method from protocol), + * add the method to the original class and associate it with the custom implementation. + */ + Method customMethod = class_getInstanceMethod(self, customSelector); + methodAdded = class_addMethod(originalClass, originalSelector, customImp, method_getTypeEncoding(customMethod)); + } + } } /* @@ -199,18 +241,23 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector */ // Validate swizzling. - if (!originalImp && !methodAdded) { - [self.traceBuffer addObject:^{ - MSLogError([MSMobileCenter logTag], - @"Cannot swizzle selector '%@' of class '%@'. You will have to explicitly call APIs from " - @"Mobile Center in your app delegate implementation.", - originalSelectorString, originalClass); - }]; - } else { - [self.traceBuffer addObject:^{ - MSLogDebug([MSMobileCenter logTag], @"Selector '%@' of class '%@' is swizzled.", originalSelectorString, - originalClass); - }]; + if (!skipped) { + if (!originalImp && !methodAdded) { + [self.traceBuffer addObject:^{ + NSString *message = [NSString + stringWithFormat:@"Cannot swizzle selector '%@' of class '%@'.", originalSelectorStr, originalClass]; + if (warningMsg) { + MSLogWarning([MSMobileCenter logTag], @"%@ %@", message, warningMsg); + } else { + MSLogError([MSMobileCenter logTag], @"%@ %@", message, remediationMsg); + } + }]; + } else { + [self.traceBuffer addObject:^{ + MSLogDebug([MSMobileCenter logTag], @"Selector '%@' of class '%@' is swizzled.", originalSelectorStr, + originalClass); + }]; + } } return originalImp; } diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h index ac1c4b2834..781d855c40 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h @@ -21,6 +21,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, class, readonly) NSArray *selectorsNotToOverride; +/** + * Dictionary of deprecated original selectors indexed by their new equivalent. + */ +@property(nonatomic, class, readonly) NSDictionary *deprecatedSelectors; + /** * Keep track of the original delegate's method implementations. */ From ea43034bdd8766e4531ed2d4a904aadc10cf36c6 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Mon, 28 Aug 2017 15:39:29 -0700 Subject: [PATCH 04/55] Remove comment about traces in MSAppDelegateForwarder --- .../Internals/AppDelegate/MSAppDelegateForwarder.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.h b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.h index 78dde3fa5a..3b13a45396 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.h +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.h @@ -41,9 +41,6 @@ NS_ASSUME_NONNULL_BEGIN /** * Flush debugging traces accumulated until now. - * TODO: We should find a way for customers to set the log level in their configuration somehow so that it'll be set at - * the time of the swizzling. This will allow having swizzling traces in real time, in that case we can remove the whole - * trace buffer mechanism. */ + (void)flushTraceBuffer; From 201dbfb4b05443ee51f1fc1cfbaacaabe2fa1a9d Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 29 Aug 2017 15:29:51 -0700 Subject: [PATCH 05/55] Hide custom properties from tvOS --- MobileCenter/MobileCenter.xcodeproj/project.pbxproj | 10 ---------- MobileCenter/MobileCenter/MSMobileCenter.h | 4 ++++ MobileCenter/MobileCenter/MSMobileCenter.m | 8 ++++++++ MobileCenter/MobileCenter/MobileCenter.h | 2 ++ MobileCenter/MobileCenterTests/MSMobileCenterTests.m | 5 +++++ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj index 0f7f8a2a94..e0a6cb3990 100644 --- a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj +++ b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj @@ -93,13 +93,11 @@ 043120781EE0BCF9007054C5 /* MSLogContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E171B591D234717000DC480 /* MSLogContainer.m */; }; 0431207B1EE0BCF9007054C5 /* MSMobileCenterErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 388993391E29B26D00C27B36 /* MSMobileCenterErrors.m */; }; 0431207C1EE0BCF9007054C5 /* MSDeviceHistoryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = B2FD53611E56501B0050F909 /* MSDeviceHistoryInfo.m */; }; - 0431207D1EE0BCF9007054C5 /* MSCustomProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = F803BBF21E8E3677004B1E7A /* MSCustomProperties.m */; }; 043120801EE0BCF9007054C5 /* MSHttpSender.m in Sources */ = {isa = PBXBuildFile; fileRef = E84B8E341D235226006FD231 /* MSHttpSender.m */; }; 043120811EE0BCF9007054C5 /* MSServiceAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = D38024051E7126F500466558 /* MSServiceAbstract.m */; }; 043120821EE0BCF9007054C5 /* MSLogManagerDefault.m in Sources */ = {isa = PBXBuildFile; fileRef = E84B8E2D1D2351DB006FD231 /* MSLogManagerDefault.m */; }; 043120831EE0BCF9007054C5 /* MSStartServiceLog.m in Sources */ = {isa = PBXBuildFile; fileRef = D38023E61E6EFC7C00466558 /* MSStartServiceLog.m */; }; 043120841EE0BCF9007054C5 /* MSSenderUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = E8753D6D1D4BE53F00241513 /* MSSenderUtil.m */; }; - 043120851EE0BCF9007054C5 /* MSCustomPropertiesLog.m in Sources */ = {isa = PBXBuildFile; fileRef = F803BBF81E8E3989004B1E7A /* MSCustomPropertiesLog.m */; }; 043120861EE0BCF9007054C5 /* MSAbstractLog.m in Sources */ = {isa = PBXBuildFile; fileRef = E88EBBEB1D2C612E007E7785 /* MSAbstractLog.m */; }; 043120871EE0BCF9007054C5 /* MSKeychainUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 045BC3161E3FD88600B6C960 /* MSKeychainUtil.m */; }; 043120881EE0BCF9007054C5 /* MSWrapperLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */; }; @@ -115,7 +113,6 @@ 0431209B1EE0BCF9007054C5 /* MSSenderCall.h in Headers */ = {isa = PBXBuildFile; fileRef = E80EB1051D50273700C9003F /* MSSenderCall.h */; }; 0431209C1EE0BCF9007054C5 /* MSSender.h in Headers */ = {isa = PBXBuildFile; fileRef = E84B8E311D235209006FD231 /* MSSender.h */; }; 0431209D1EE0BCF9007054C5 /* MSServiceCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C758D1D64DF2500D68CC1 /* MSServiceCommon.h */; }; - 043120A01EE0BCF9007054C5 /* MSCustomProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = F803BBF11E8E3677004B1E7A /* MSCustomProperties.h */; settings = {ATTRIBUTES = (Public, ); }; }; 043120A21EE0BCF9007054C5 /* MSMobileCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E0401551D1C9AAA0051BCFA /* MSMobileCenter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 043120A31EE0BCF9007054C5 /* MSLogManagerDefaultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 04FD126E1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h */; }; 043120A41EE0BCF9007054C5 /* MSMobileCenterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 38E1B6791DDE3FDF000EFED1 /* MSMobileCenterPrivate.h */; }; @@ -158,7 +155,6 @@ 043120D51EE0BCF9007054C5 /* MSChannelDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5949380E604D45340244FEF1 /* MSChannelDelegate.h */; }; 043120D61EE0BCF9007054C5 /* MSIngestionSender.h in Headers */ = {isa = PBXBuildFile; fileRef = BA6824A001520825F18DFC42 /* MSIngestionSender.h */; }; 0446DF021F3B864600C8E338 /* MSMockOriginalAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */; }; - 0446DF031F3B864600C8E338 /* MSCustomPropertiesLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F803BC391E8E6963004B1E7A /* MSCustomPropertiesLogTests.m */; }; 0446DF041F3B864600C8E338 /* MSMockUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = D377A30C1E83A05900B2C97A /* MSMockUserDefaults.m */; }; 0446DF051F3B864600C8E338 /* MSLogWithPropertiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 045660FA1D99EEEB002F7055 /* MSLogWithPropertiesTests.m */; }; 0446DF061F3B864600C8E338 /* MSDeviceLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E3E2CC01D3596AE00B1EE50 /* MSDeviceLogTests.m */; }; @@ -181,7 +177,6 @@ 0446DF171F3B864600C8E338 /* MSServiceAbstractTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 387C75951D64EE1900D68CC1 /* MSServiceAbstractTests.m */; }; 0446DF181F3B864600C8E338 /* MSChannelConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E48A5A31D3831FE006E8B5F /* MSChannelConfigurationTests.m */; }; 0446DF191F3B864600C8E338 /* MSLoggerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B24F3F161D93A3FF00827213 /* MSLoggerTests.m */; }; - 0446DF1A1F3B864600C8E338 /* MSCustomPropertiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F803BC371E8E6927004B1E7A /* MSCustomPropertiesTests.m */; }; 0446DF1B1F3B864600C8E338 /* MSSenderUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04B7BBEE1E5FAD4D001A0CE1 /* MSSenderUtilTests.m */; }; 0446DF1C1F3B864600C8E338 /* MSMockLog.m in Sources */ = {isa = PBXBuildFile; fileRef = E88D17051D35B6B500A5EA57 /* MSMockLog.m */; }; 0446DF1D1F3B864600C8E338 /* MSLogManagerDefaultTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E48A5A61D383893006E8B5F /* MSLogManagerDefaultTests.m */; }; @@ -1235,7 +1230,6 @@ B2CD74C91F22BEC70070E7DF /* MSDBStoragePrivate.h in Headers */, 0431209D1EE0BCF9007054C5 /* MSServiceCommon.h in Headers */, B2181B7B1F26852600D2EEAE /* MSWrapperSdk.h in Headers */, - 043120A01EE0BCF9007054C5 /* MSCustomProperties.h in Headers */, 043120A21EE0BCF9007054C5 /* MSMobileCenter.h in Headers */, 043120A31EE0BCF9007054C5 /* MSLogManagerDefaultPrivate.h in Headers */, 043120A41EE0BCF9007054C5 /* MSMobileCenterPrivate.h in Headers */, @@ -1719,7 +1713,6 @@ 045C0BEF1EEB12300038FD6B /* MSAppDelegateForwarder.m in Sources */, B2CD74A51F22BE270070E7DF /* MSUtility.m in Sources */, 0431207C1EE0BCF9007054C5 /* MSDeviceHistoryInfo.m in Sources */, - 0431207D1EE0BCF9007054C5 /* MSCustomProperties.m in Sources */, B2181B7C1F26852B00D2EEAE /* MSWrapperSdk.m in Sources */, 041EFD281EE1CAA6006DCD56 /* MSDevice.m in Sources */, 043120801EE0BCF9007054C5 /* MSHttpSender.m in Sources */, @@ -1729,7 +1722,6 @@ 043120831EE0BCF9007054C5 /* MSStartServiceLog.m in Sources */, 043120841EE0BCF9007054C5 /* MSSenderUtil.m in Sources */, B2CD74C01F22BE270070E7DF /* MSUtility+File.m in Sources */, - 043120851EE0BCF9007054C5 /* MSCustomPropertiesLog.m in Sources */, 043120861EE0BCF9007054C5 /* MSAbstractLog.m in Sources */, 043120871EE0BCF9007054C5 /* MSKeychainUtil.m in Sources */, B2CD748A1F22BD910070E7DF /* MSLogDBStorage.m in Sources */, @@ -1750,7 +1742,6 @@ buildActionMask = 2147483647; files = ( 0446DF021F3B864600C8E338 /* MSMockOriginalAppDelegate.m in Sources */, - 0446DF031F3B864600C8E338 /* MSCustomPropertiesLogTests.m in Sources */, 0446DF041F3B864600C8E338 /* MSMockUserDefaults.m in Sources */, 0446DF051F3B864600C8E338 /* MSLogWithPropertiesTests.m in Sources */, 0446DF061F3B864600C8E338 /* MSDeviceLogTests.m in Sources */, @@ -1773,7 +1764,6 @@ 0446DF171F3B864600C8E338 /* MSServiceAbstractTests.m in Sources */, 0446DF181F3B864600C8E338 /* MSChannelConfigurationTests.m in Sources */, 0446DF191F3B864600C8E338 /* MSLoggerTests.m in Sources */, - 0446DF1A1F3B864600C8E338 /* MSCustomPropertiesTests.m in Sources */, 0446DF1B1F3B864600C8E338 /* MSSenderUtilTests.m in Sources */, 0446DF1C1F3B864600C8E338 /* MSMockLog.m in Sources */, 0446DF1D1F3B864600C8E338 /* MSLogManagerDefaultTests.m in Sources */, diff --git a/MobileCenter/MobileCenter/MSMobileCenter.h b/MobileCenter/MobileCenter/MSMobileCenter.h index 9fa20227fd..57cc185251 100644 --- a/MobileCenter/MobileCenter/MSMobileCenter.h +++ b/MobileCenter/MobileCenter/MSMobileCenter.h @@ -3,7 +3,9 @@ #import "MSConstants.h" @class MSWrapperSdk; +#if !TARGET_OS_TV @class MSCustomProperties; +#endif @interface MSMobileCenter : NSObject @@ -96,12 +98,14 @@ */ + (void)setWrapperSdk:(MSWrapperSdk *)wrapperSdk; +#if !TARGET_OS_TV /** * Set the custom properties. * * @param customProperties Custom properties object. */ + (void)setCustomProperties:(MSCustomProperties *)customProperties; +#endif /** * Check whether the application delegate forwarder is enabled or not. diff --git a/MobileCenter/MobileCenter/MSMobileCenter.m b/MobileCenter/MobileCenter/MSMobileCenter.m index 67080036d7..39525fa102 100644 --- a/MobileCenter/MobileCenter/MSMobileCenter.m +++ b/MobileCenter/MobileCenter/MSMobileCenter.m @@ -9,9 +9,11 @@ #import "MSLogger.h" #import "MSMobileCenterInternal.h" #import "MSStartServiceLog.h" +#if !TARGET_OS_TV #import "MSCustomProperties.h" #import "MSCustomPropertiesLog.h" #import "MSCustomPropertiesPrivate.h" +#endif // Singleton static MSMobileCenter *sharedInstance = nil; @@ -109,9 +111,11 @@ + (void)setWrapperSdk:(MSWrapperSdk *)wrapperSdk { [[MSDeviceTracker sharedInstance] setWrapperSdk:wrapperSdk]; } +#if !TARGET_OS_TV + (void)setCustomProperties:(MSCustomProperties *)customProperties { [[self sharedInstance] setCustomProperties:customProperties]; } +#endif /** * Check if the debugger is attached @@ -282,6 +286,7 @@ - (void)setLogUrl:(NSString *)logUrl { } } +#if !TARGET_OS_TV - (void)setCustomProperties:(MSCustomProperties *)customProperties { if (!customProperties || customProperties.properties == 0) { MSLogError([MSMobileCenter logTag], @"Custom properties may not be null or empty"); @@ -289,6 +294,7 @@ - (void)setCustomProperties:(MSCustomProperties *)customProperties { } [self sendCustomPropertiesLog:customProperties.properties]; } +#endif - (void)setEnabled:(BOOL)isEnabled { self.enabledStateUpdating = YES; @@ -407,6 +413,7 @@ - (void)sendStartServiceLog:(NSArray *)servicesNames { [self.logManager processLog:serviceLog forGroupId:kMSGroupId]; } +#if !TARGET_OS_TV - (void)sendCustomPropertiesLog:(NSDictionary *)properties { MSCustomPropertiesLog *customPropertiesLog = [MSCustomPropertiesLog new]; customPropertiesLog.properties = properties; @@ -414,6 +421,7 @@ - (void)sendCustomPropertiesLog:(NSDictionary *)properti // FIXME: withPriority parameter need to be removed on merge. [self.logManager processLog:customPropertiesLog forGroupId:kMSGroupId]; } +#endif + (void)resetSharedInstance { onceToken = 0; // resets the once_token so dispatch_once will run again diff --git a/MobileCenter/MobileCenter/MobileCenter.h b/MobileCenter/MobileCenter/MobileCenter.h index f74cc0d3ae..ff3a5c5102 100644 --- a/MobileCenter/MobileCenter/MobileCenter.h +++ b/MobileCenter/MobileCenter/MobileCenter.h @@ -10,4 +10,6 @@ #import "MSServiceAbstract.h" #import "MSWrapperSdk.h" #import "MSMobileCenterErrors.h" +#if !TARGET_OS_TV #import "MSCustomProperties.h" +#endif diff --git a/MobileCenter/MobileCenterTests/MSMobileCenterTests.m b/MobileCenter/MobileCenterTests/MSMobileCenterTests.m index c09a8feacc..d1e37b78fb 100644 --- a/MobileCenter/MobileCenterTests/MSMobileCenterTests.m +++ b/MobileCenter/MobileCenterTests/MSMobileCenterTests.m @@ -1,5 +1,8 @@ +#include +#if !TARGET_OS_TV #import "MSCustomProperties.h" #import "MSCustomPropertiesLog.h" +#endif #import "MSLogManagerDefault.h" #import "MSMobileCenter.h" #import "MSMobileCenterInternal.h" @@ -146,6 +149,7 @@ - (void)testDefaultLogUrl { XCTAssertTrue([[[MSMobileCenter sharedInstance] logUrl] isEqualToString:@"https://in.mobile.azure.com"]); } +#if !TARGET_OS_TV - (void)testSetCustomProperties { // If @@ -172,6 +176,7 @@ - (void)testSetCustomProperties { // Then OCMVerifyAll(logManager); } +#endif - (void)testConfigureWithAppSecret { [MSMobileCenter configureWithAppSecret:@"App-Secret"]; From 435879abe311fe05cd1b6e76d5fc53b76a7f32d6 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Wed, 30 Aug 2017 10:55:01 -0700 Subject: [PATCH 06/55] Bump version to 0.12.2 --- Config/Global.xcconfig | 2 +- Documentation/iOS/MobileCenter/.jazzy.yaml | 2 +- Documentation/iOS/MobileCenterAnalytics/.jazzy.yaml | 2 +- Documentation/iOS/MobileCenterCrashes/.jazzy.yaml | 2 +- Documentation/iOS/MobileCenterDistribute/.jazzy.yaml | 2 +- Documentation/iOS/MobileCenterPush/.jazzy.yaml | 2 +- Documentation/macOS/MobileCenter/.jazzy.yaml | 2 +- Documentation/macOS/MobileCenterAnalytics/.jazzy.yaml | 2 +- Documentation/macOS/MobileCenterCrashes/.jazzy.yaml | 2 +- Documentation/macOS/MobileCenterPush/.jazzy.yaml | 2 +- Documentation/tvOS/MobileCenter/.jazzy.yaml | 2 +- Documentation/tvOS/MobileCenterAnalytics/.jazzy.yaml | 2 +- Documentation/tvOS/MobileCenterCrashes/.jazzy.yaml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Config/Global.xcconfig b/Config/Global.xcconfig index 5a242cceb8..da6c8777c4 100644 --- a/Config/Global.xcconfig +++ b/Config/Global.xcconfig @@ -1,5 +1,5 @@ BUILD_NUMBER = 1 -VERSION_STRING = 0.12.1 +VERSION_STRING = 0.12.2 // :Mark: Architectures MS_WATCH_ARCHS = armv7k diff --git a/Documentation/iOS/MobileCenter/.jazzy.yaml b/Documentation/iOS/MobileCenter/.jazzy.yaml index 495b247ece..3efb7cbdfe 100644 --- a/Documentation/iOS/MobileCenter/.jazzy.yaml +++ b/Documentation/iOS/MobileCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: MobileCenter -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/MobileCenterAnalytics/.jazzy.yaml b/Documentation/iOS/MobileCenterAnalytics/.jazzy.yaml index 1cc6c85a5a..41280ef0f8 100644 --- a/Documentation/iOS/MobileCenterAnalytics/.jazzy.yaml +++ b/Documentation/iOS/MobileCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: MobileCenterAnalytics -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/MobileCenterCrashes/.jazzy.yaml b/Documentation/iOS/MobileCenterCrashes/.jazzy.yaml index 60fe27634f..f50946fe69 100644 --- a/Documentation/iOS/MobileCenterCrashes/.jazzy.yaml +++ b/Documentation/iOS/MobileCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: Crashes -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/MobileCenterDistribute/.jazzy.yaml b/Documentation/iOS/MobileCenterDistribute/.jazzy.yaml index d36d1cd5fc..dfde796dad 100644 --- a/Documentation/iOS/MobileCenterDistribute/.jazzy.yaml +++ b/Documentation/iOS/MobileCenterDistribute/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: Distribute -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/MobileCenterPush/.jazzy.yaml b/Documentation/iOS/MobileCenterPush/.jazzy.yaml index 783ed41a53..eb6e5a106c 100644 --- a/Documentation/iOS/MobileCenterPush/.jazzy.yaml +++ b/Documentation/iOS/MobileCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: MobileCenterPush -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/MobileCenter/.jazzy.yaml b/Documentation/macOS/MobileCenter/.jazzy.yaml index ef9e7d71c7..95dc4057dd 100644 --- a/Documentation/macOS/MobileCenter/.jazzy.yaml +++ b/Documentation/macOS/MobileCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: MobileCenter -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/MobileCenterAnalytics/.jazzy.yaml b/Documentation/macOS/MobileCenterAnalytics/.jazzy.yaml index 64e2d4f301..018cebd119 100644 --- a/Documentation/macOS/MobileCenterAnalytics/.jazzy.yaml +++ b/Documentation/macOS/MobileCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: MobileCenterAnalytics -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/MobileCenterCrashes/.jazzy.yaml b/Documentation/macOS/MobileCenterCrashes/.jazzy.yaml index ddf03982c1..fae1af185c 100644 --- a/Documentation/macOS/MobileCenterCrashes/.jazzy.yaml +++ b/Documentation/macOS/MobileCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: Crashes -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/MobileCenterPush/.jazzy.yaml b/Documentation/macOS/MobileCenterPush/.jazzy.yaml index 199f4d707a..62e590304d 100644 --- a/Documentation/macOS/MobileCenterPush/.jazzy.yaml +++ b/Documentation/macOS/MobileCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: MobileCenterPush -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/MobileCenter/.jazzy.yaml b/Documentation/tvOS/MobileCenter/.jazzy.yaml index d572cb0478..e393301bd7 100644 --- a/Documentation/tvOS/MobileCenter/.jazzy.yaml +++ b/Documentation/tvOS/MobileCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: MobileCenter -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/MobileCenterAnalytics/.jazzy.yaml b/Documentation/tvOS/MobileCenterAnalytics/.jazzy.yaml index 8ad1057d01..c651e21d37 100644 --- a/Documentation/tvOS/MobileCenterAnalytics/.jazzy.yaml +++ b/Documentation/tvOS/MobileCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: MobileCenterAnalytics -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/MobileCenterCrashes/.jazzy.yaml b/Documentation/tvOS/MobileCenterCrashes/.jazzy.yaml index b9b94628d8..f057b8f493 100644 --- a/Documentation/tvOS/MobileCenterCrashes/.jazzy.yaml +++ b/Documentation/tvOS/MobileCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: Crashes -module_version: 0.12.1 +module_version: 0.12.2 author: Microsoft Corp author_url: http://www.microsoft.com From 759740f82585650cc21df822f5a7126d562e3141 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 30 Aug 2017 11:06:42 -0700 Subject: [PATCH 07/55] Replace app secrets --- SasquatchMac/SasquatchMacObjC/AppDelegate.m | 2 +- SasquatchMac/SasquatchMacSwift/AppDelegate.swift | 2 +- SasquatchTV/SasquatchTVObjC/AppDelegate.m | 2 +- SasquatchTV/SasquatchTVSwift/AppDelegate.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SasquatchMac/SasquatchMacObjC/AppDelegate.m b/SasquatchMac/SasquatchMacObjC/AppDelegate.m index 5521c7d273..9f444251cf 100644 --- a/SasquatchMac/SasquatchMacObjC/AppDelegate.m +++ b/SasquatchMac/SasquatchMacObjC/AppDelegate.m @@ -19,7 +19,7 @@ - (instancetype)init { [self setupPush]; // Start MobileCenter. - [MSMobileCenter start:@"8649b73e-6df0-4985-a039-8ab1453d44f3" + [MSMobileCenter start:@"7c9bde90-6f08-438d-af98-d8c6cc92afd2" withServices:@[ [MSAnalytics class], [MSCrashes class], [MSPush class] ]]; [MobileCenterProvider shared].mobileCenter = [[MobileCenterDelegateObjC alloc] init]; return self; diff --git a/SasquatchMac/SasquatchMacSwift/AppDelegate.swift b/SasquatchMac/SasquatchMacSwift/AppDelegate.swift index 0a6783ddc8..e03fb67067 100644 --- a/SasquatchMac/SasquatchMacSwift/AppDelegate.swift +++ b/SasquatchMac/SasquatchMacSwift/AppDelegate.swift @@ -37,7 +37,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, MSCrashesDelegate, MSPushDel // Start MobileCenter. MSMobileCenter.setLogLevel(MSLogLevel.verbose) MSMobileCenter.setLogUrl("https://in-integration.dev.avalanch.es") - MSMobileCenter.start("7ee5f412-02f7-45ea-a49c-b4ebf2911325", withServices : [ MSAnalytics.self, MSCrashes.self, MSPush.self ]) + MSMobileCenter.start("c62b8db6-191e-496a-b1a1-267b9bf326c4", withServices : [ MSAnalytics.self, MSCrashes.self, MSPush.self ]) MobileCenterProvider.shared().mobileCenter = MobileCenterDelegateSwift() } diff --git a/SasquatchTV/SasquatchTVObjC/AppDelegate.m b/SasquatchTV/SasquatchTVObjC/AppDelegate.m index 9e11d65007..6d5fd56aec 100644 --- a/SasquatchTV/SasquatchTVObjC/AppDelegate.m +++ b/SasquatchTV/SasquatchTVObjC/AppDelegate.m @@ -16,7 +16,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [MSMobileCenter setLogLevel:MSLogLevelVerbose]; [MSMobileCenter setLogUrl:@"https://in-integration.dev.avalanch.es"]; - [MSMobileCenter start:@"7ee5f412-02f7-45ea-a49c-b4ebf2911325" withServices:@[ [MSAnalytics class], [MSCrashes class] ]]; + [MSMobileCenter start:@"68065a02-edbb-4fc3-a323-3b8ca2beae80" withServices:@[ [MSAnalytics class], [MSCrashes class] ]]; [self crashes]; [self setMobileCenterDelegate]; return YES; diff --git a/SasquatchTV/SasquatchTVSwift/AppDelegate.swift b/SasquatchTV/SasquatchTVSwift/AppDelegate.swift index 5e2858bf19..5d820384bf 100644 --- a/SasquatchTV/SasquatchTVSwift/AppDelegate.swift +++ b/SasquatchTV/SasquatchTVSwift/AppDelegate.swift @@ -13,7 +13,7 @@ class AppDelegate : UIResponder, UIApplicationDelegate, MSCrashesDelegate { // Override point for customization after application launch. MSMobileCenter.setLogLevel(MSLogLevel.verbose); - MSMobileCenter.start("0dbca56b-b9ae-4d53-856a-7c2856137d85", withServices : [MSAnalytics.self, MSCrashes.self]); + MSMobileCenter.start("fbdeeff6-a549-4653-9f6d-f97dfe7f07b4", withServices : [MSAnalytics.self, MSCrashes.self]); // Crashes Delegate. MSCrashes.setDelegate(self) From ea4de8507240e1aaf5fa2186770e7d3190ff251e Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 30 Aug 2017 11:08:04 -0700 Subject: [PATCH 08/55] Address TODO for macOS environment --- .../MobileCenter/Internals/Util/MSUtility+Environment.m | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/Util/MSUtility+Environment.m b/MobileCenter/MobileCenter/Internals/Util/MSUtility+Environment.m index fba2786be4..8dd8d5518b 100644 --- a/MobileCenter/MobileCenter/Internals/Util/MSUtility+Environment.m +++ b/MobileCenter/MobileCenter/Internals/Util/MSUtility+Environment.m @@ -8,11 +8,7 @@ @implementation MSUtility (Environment) + (MSEnvironment)currentAppEnvironment { -#if TARGET_OS_SIMULATOR - return MSEnvironmentOther; -#elif TARGET_OS_OSX - - // TODO: This is not implemented for macOS. +#if TARGET_OS_SIMULATOR || TARGET_OS_OSX return MSEnvironmentOther; #else From 0a614fdbdaaca8e723d9db08b7849f3ed32dab43 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Wed, 30 Aug 2017 12:56:22 -0700 Subject: [PATCH 09/55] =?UTF-8?q?Exclude=20disablemachExceptionHandler=20f?= =?UTF-8?q?rom=20header=20for=20tvOS=20and=20make=20sure=20it=E2=80=99s=20?= =?UTF-8?q?not=20enabled=20when=20initializing=20MSCrashes=20on=20tvOS.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Internals/MSCrashesPrivate.h | 3 --- .../MobileCenterCrashes/MSCrashes.h | 6 ++++-- .../MobileCenterCrashes/MSCrashes.mm | 16 ++++++++++------ .../MobileCenterCrashesTests/MSCrashesTests.mm | 10 +++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesPrivate.h b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesPrivate.h index 143f371e79..f19291c29a 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesPrivate.h +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesPrivate.h @@ -70,10 +70,7 @@ typedef struct MSCrashesCallbacks { MSCrashesPostCrashSignalCallback handleSignal; } MSCrashesCallbacks; -// TODO: Mach exception handler is not supported on tvOS. -#if !TARGET_OS_TV @property(nonatomic, assign, getter=isMachExceptionHandlerEnabled) BOOL enableMachExceptionHandler; -#endif /** * A list containing all crash files that currently stored on disk for this app. diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.h b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.h index 394b3b87ab..19bbdb9679 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.h +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.h @@ -91,7 +91,6 @@ typedef NS_ENUM(NSUInteger, MSUserConfirmation) { /// @name Configuration ///----------------------------------------------------------------------------- -// TODO: Mach exception handler is not supported on tvOS. #if !TARGET_OS_TV /** * Disable the Mach exception server. @@ -108,7 +107,10 @@ typedef NS_ENUM(NSUInteger, MSUserConfirmation) { * `MSCrashes.disableMachExceptionHandler()` * `MSMobileCenter.start("YOUR_APP_ID", withServices: [MSAnalytics.self, MSCrashes.self])` * - * @discussion This can be useful to disable the Mach exception handler when you are debugging the Crashes service while + * tvOS does not support the Mach exception handler, thus crashes that are caused by stack overflows cannot + * be detected. As a result, disabling the Mach exception server is not available in the tvOS SDK. + * + * @discussion It can be useful to disable the Mach exception handler when you are debugging the Crashes service while * developing, especially when you attach the debugger to your application after launch. */ + (void)disableMachExceptionHandler; diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm index da125bdbab..deb9d71764 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm @@ -229,13 +229,15 @@ + (MSErrorReport *_Nullable)lastSessionCrashReport { return [[self sharedInstance] getLastSessionCrashReport]; } -/* This can never be binded to Xamarin */ -// TODO: Mach exception handler is not supported on tvOS. -#if !TARGET_OS_TV +/* + * This can never be bound to Xamarin. + * + * This method is not part of the publicly available on tvOS as Mach exception handling is not possible on tvOS. + * The property is NO by default there. + */ + (void)disableMachExceptionHandler { [[self sharedInstance] setEnableMachExceptionHandler:NO]; } -#endif + (void)setDelegate:(_Nullable id)delegate { [[self sharedInstance] setDelegate:delegate]; @@ -252,7 +254,6 @@ - (instancetype)init { _analyzerInProgressFile = [_crashesDir URLByAppendingPathComponent:kMSAnalyzerFilename]; _didCrashInLastSession = NO; - // TODO: Mach exception handler is not supported on tvOS. #if !TARGET_OS_TV _enableMachExceptionHandler = YES; #endif @@ -391,6 +392,10 @@ - (MSInitializationPriority)initializationPriority { return MSInitializationPriorityMax; } +- (void)setEnableMachExceptionHandler:(BOOL)enableMachExceptionHandler { + _enableMachExceptionHandler = enableMachExceptionHandler; +} + #pragma mark - MSLogManagerDelegate /** @@ -561,7 +566,6 @@ - (void)configureCrashReporterWithUncaughtExceptionHandlerEnabled:(BOOL)enableUn PLCrashReporterSignalHandlerType signalHandlerType = PLCrashReporterSignalHandlerTypeBSD; - // TODO: Mach exception handler is not supported on tvOS. #if !TARGET_OS_TV if (self.isMachExceptionHandlerEnabled) { signalHandlerType = PLCrashReporterSignalHandlerTypeMach; diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index a46fed5bd7..2cadfed364 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -494,7 +494,7 @@ - (void)testInitializationPriorityCorrect { XCTAssertTrue([[MSCrashes sharedInstance] initializationPriority] == MSInitializationPriorityMax); } -// TODO: Mach exception handler is not supported on tvOS. +// The Mach exception handler is not supported on tvOS. #if !TARGET_OS_TV - (void)testDisableMachExceptionWorks { @@ -518,6 +518,14 @@ - (void)testDisableMachExceptionWorks { } #endif +#if TARGET_OS_TV +- (void) testMachExceptionHandlerDisabledOnTvOS { + + // Then + XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); +} +#endif + - (void)testAbstractErrorLogSerialization { MSAbstractErrorLog *log = [MSAbstractErrorLog new]; From 54470d9e2f9a2f8737d0fd168e807285c4666cb2 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 30 Aug 2017 17:37:56 -0700 Subject: [PATCH 10/55] Change date format for timestamp with milliseconds --- MobileCenter/MobileCenter/Internals/Util/MSUtility+Date.m | 2 +- MobileCenter/MobileCenterTests/MSCustomPropertiesLogTests.m | 2 +- .../MobileCenterAnalyticsTests/MSEventLogTests.m | 2 +- .../MobileCenterAnalyticsTests/MSPageLogTests.m | 2 +- .../MobileCenterAnalyticsTests/MSStartSessionLogTests.m | 2 +- .../MobileCenterCrashesTests/MSAppleErrorLogTests.m | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/Util/MSUtility+Date.m b/MobileCenter/MobileCenter/Internals/Util/MSUtility+Date.m index 9de9ac8985..639d935dde 100644 --- a/MobileCenter/MobileCenter/Internals/Util/MSUtility+Date.m +++ b/MobileCenter/MobileCenter/Internals/Util/MSUtility+Date.m @@ -17,7 +17,7 @@ + (NSString *)dateToISO8601:(NSDate *)date { dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setLocale:[NSLocale systemLocale]]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; - [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; } return [dateFormatter stringFromDate:date]; } diff --git a/MobileCenter/MobileCenterTests/MSCustomPropertiesLogTests.m b/MobileCenter/MobileCenterTests/MSCustomPropertiesLogTests.m index 451be770c8..5026fda93c 100644 --- a/MobileCenter/MobileCenterTests/MSCustomPropertiesLogTests.m +++ b/MobileCenter/MobileCenterTests/MSCustomPropertiesLogTests.m @@ -46,7 +46,7 @@ - (void)testSerializingToDictionaryWorks { NSArray *actualProperties = actual[@"properties"]; assertThat(actualProperties, hasCountOf(5)); NSArray *needProperties = @[@{@"name": @"t1", @"type": @"string", @"value": string}, - @{@"name": @"t2", @"type": @"date_time", @"value": @"1970-01-01T00:00:00Z"}, + @{@"name": @"t2", @"type": @"date_time", @"value": @"1970-01-01T00:00:00.000Z"}, @{@"name": @"t3", @"type": @"number", @"value": number}, @{@"name": @"t4", @"type": @"boolean", @"value": boolean}, @{@"name": @"t5", @"type": @"clear"}]; diff --git a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSEventLogTests.m b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSEventLogTests.m index 9982969736..930c36ba25 100644 --- a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSEventLogTests.m +++ b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSEventLogTests.m @@ -52,7 +52,7 @@ - (void)testSerializingEventToDictionaryWorks { assertThat(actual[@"type"], equalTo(typeName)); assertThat(actual[@"properties"], equalTo(properties)); assertThat(actual[@"device"], notNilValue()); - assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42Z")); + assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42.000Z")); } - (void)testNSCodingSerializationAndDeserializationWorks { diff --git a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSPageLogTests.m b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSPageLogTests.m index 13871c8278..7736bd33e8 100644 --- a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSPageLogTests.m +++ b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSPageLogTests.m @@ -49,7 +49,7 @@ - (void)testSerializingPageToDictionaryWorks { assertThat(actual[@"type"], equalTo(typeName)); assertThat(actual[@"properties"], equalTo(properties)); assertThat(actual[@"device"], notNilValue()); - assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42Z")); + assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42.000Z")); } - (void)testNSCodingSerializationAndDeserializationWorks { diff --git a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSStartSessionLogTests.m b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSStartSessionLogTests.m index 9af454e9f1..b3833dc265 100644 --- a/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSStartSessionLogTests.m +++ b/MobileCenterAnalytics/MobileCenterAnalyticsTests/MSStartSessionLogTests.m @@ -41,7 +41,7 @@ - (void)testSerializingSessionToDictionaryWorks { assertThat(actual, notNilValue()); assertThat(actual[@"type"], equalTo(typeName)); assertThat(actual[@"device"], notNilValue()); - assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42Z")); + assertThat(actual[@"timestamp"], equalTo(@"1970-01-01T00:00:42.000Z")); } - (void)testNSCodingSerializationAndDeserializationWorks { diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSAppleErrorLogTests.m b/MobileCenterCrashes/MobileCenterCrashesTests/MSAppleErrorLogTests.m index f7c3e03fe7..5db844b6ff 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSAppleErrorLogTests.m +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSAppleErrorLogTests.m @@ -84,7 +84,7 @@ - (void)testSerializationToDictionaryWorks { assertThat(actual[@"error_thread_id"], equalTo(self.sut.errorThreadId)); assertThat(actual[@"error_thread_name"], equalTo(self.sut.errorThreadName)); XCTAssertEqual([actual[@"fatal"] boolValue], self.sut.fatal); - assertThat(actual[@"app_launch_timestamp"], equalTo(@"1970-01-01T00:00:42Z")); + assertThat(actual[@"app_launch_timestamp"], equalTo(@"1970-01-01T00:00:42.000Z")); assertThat(actual[@"architecture"], equalTo(self.sut.architecture)); // Exception fields. From ac3105c5401ff2ac0729b33a04da89abd6c5901b Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Thu, 31 Aug 2017 13:59:47 -0700 Subject: [PATCH 11/55] Update Sasquatch app secret for macOS --- SasquatchMac/SasquatchMacObjC/AppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SasquatchMac/SasquatchMacObjC/AppDelegate.m b/SasquatchMac/SasquatchMacObjC/AppDelegate.m index 9f444251cf..d464e89a7c 100644 --- a/SasquatchMac/SasquatchMacObjC/AppDelegate.m +++ b/SasquatchMac/SasquatchMacObjC/AppDelegate.m @@ -19,7 +19,7 @@ - (instancetype)init { [self setupPush]; // Start MobileCenter. - [MSMobileCenter start:@"7c9bde90-6f08-438d-af98-d8c6cc92afd2" + [MSMobileCenter start:@"4b3f7d94-c64b-4aac-94f5-894c55c64bfe" withServices:@[ [MSAnalytics class], [MSCrashes class], [MSPush class] ]]; [MobileCenterProvider shared].mobileCenter = [[MobileCenterDelegateObjC alloc] init]; return self; From f2492fd9da96599f842f0fd99807219ce7864026 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Fri, 1 Sep 2017 09:43:28 -0700 Subject: [PATCH 12/55] Address PR feedback --- .../MobileCenterCrashes/MSCrashes.mm | 2 +- .../MSCrashesTests.mm | 27 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm index deb9d71764..7be6b47c62 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm @@ -232,7 +232,7 @@ + (MSErrorReport *_Nullable)lastSessionCrashReport { /* * This can never be bound to Xamarin. * - * This method is not part of the publicly available on tvOS as Mach exception handling is not possible on tvOS. + * This method is not part of the publicly available APIs on tvOS as Mach exception handling is not possible on tvOS. * The property is NO by default there. */ + (void)disableMachExceptionHandler { diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index 2cadfed364..0f976deb31 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -495,35 +495,34 @@ - (void)testInitializationPriorityCorrect { } // The Mach exception handler is not supported on tvOS. -#if !TARGET_OS_TV +#if TARGET_OS_TV +- (void) testMachExceptionHandlerDisabledOnTvOS { + + // Then + XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); +} +#else - (void)testDisableMachExceptionWorks { - + // Then XCTAssertTrue([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); - + // When [MSCrashes disableMachExceptionHandler]; - + // Then XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); - + // Then XCTAssertTrue([self.sut isMachExceptionHandlerEnabled]); - + // When [self.sut setEnableMachExceptionHandler:NO]; - + // Then XCTAssertFalse([self.sut isMachExceptionHandlerEnabled]); } -#endif -#if TARGET_OS_TV -- (void) testMachExceptionHandlerDisabledOnTvOS { - - // Then - XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); -} #endif - (void)testAbstractErrorLogSerialization { From 9622ad6ea52b16bbfb3cb084610596a8d7d4a78a Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Tue, 5 Sep 2017 09:07:26 -0700 Subject: [PATCH 13/55] Improve AppDelegateForwarder tests, build up new classes for each tests --- .../MobileCenter.xcodeproj/project.pbxproj | 20 - .../AppDelegate/MSAppDelegateForwarder.m | 8 + .../MSAppDelegateForwarderPrivate.h | 5 + .../MSAppDelegateForwarderTests.m | 1016 ++++++++++------- .../MobileCenterTests/MSMobileCenterTests.m | 2 - .../Util/MSMockCustomAppDelegate.h | 32 - .../Util/MSMockCustomAppDelegate.m | 86 -- .../Util/MSMockOriginalAppDelegate.h | 26 - .../Util/MSMockOriginalAppDelegate.m | 63 - 9 files changed, 611 insertions(+), 647 deletions(-) delete mode 100644 MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.h delete mode 100644 MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.m delete mode 100644 MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.h delete mode 100644 MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.m diff --git a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj index 0f7f8a2a94..b2e529da26 100644 --- a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj +++ b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj @@ -157,12 +157,10 @@ 043120D31EE0BCF9007054C5 /* MSKeychainUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 045BC3181E3FD8AC00B6C960 /* MSKeychainUtil.h */; }; 043120D51EE0BCF9007054C5 /* MSChannelDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5949380E604D45340244FEF1 /* MSChannelDelegate.h */; }; 043120D61EE0BCF9007054C5 /* MSIngestionSender.h in Headers */ = {isa = PBXBuildFile; fileRef = BA6824A001520825F18DFC42 /* MSIngestionSender.h */; }; - 0446DF021F3B864600C8E338 /* MSMockOriginalAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */; }; 0446DF031F3B864600C8E338 /* MSCustomPropertiesLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F803BC391E8E6963004B1E7A /* MSCustomPropertiesLogTests.m */; }; 0446DF041F3B864600C8E338 /* MSMockUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = D377A30C1E83A05900B2C97A /* MSMockUserDefaults.m */; }; 0446DF051F3B864600C8E338 /* MSLogWithPropertiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 045660FA1D99EEEB002F7055 /* MSLogWithPropertiesTests.m */; }; 0446DF061F3B864600C8E338 /* MSDeviceLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E3E2CC01D3596AE00B1EE50 /* MSDeviceLogTests.m */; }; - 0446DF071F3B864600C8E338 /* MSMockCustomAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3872CA971ECA0B04006B2E3B /* MSMockCustomAppDelegate.m */; }; 0446DF081F3B864600C8E338 /* MSDeviceTrackerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */; }; 0446DF091F3B864600C8E338 /* MSAppDelegateForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */; }; 0446DF0A1F3B864600C8E338 /* MSChannelDefaultTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EB1F40D1D2443B7005F9F99 /* MSChannelDefaultTests.m */; }; @@ -293,8 +291,6 @@ 04873E831F2FCE3E00A13AFF /* MSAppDelegateForwarder.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C4471F1ECE5352002E1B11 /* MSAppDelegateForwarder.m */; }; 04873E841F2FCF9000A13AFF /* MSAppDelegateForwarderPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C447201ECE5352002E1B11 /* MSAppDelegateForwarderPrivate.h */; }; 04873E871F2FDDEC00A13AFF /* MSAppDelegateForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */; }; - 04873E881F2FDECE00A13AFF /* MSMockOriginalAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */; }; - 04873E891F2FDFD500A13AFF /* MSMockCustomAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3872CA971ECA0B04006B2E3B /* MSMockCustomAppDelegate.m */; }; 0499F8551EDF979700C3EDDA /* MSLogWithProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 3844FF191E8C2716003E9194 /* MSLogWithProperties.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0499F8561EDF979A00C3EDDA /* MSDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 3844FF1A1E8C2716003E9194 /* MSDevice.m */; }; 0499F8571EDF979D00C3EDDA /* MSDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 3844FF1B1E8C2716003E9194 /* MSDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -317,7 +313,6 @@ 3592ABA81DC90E3600EF4592 /* MSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3592ABA61DC90E3600EF4592 /* MSLogger.m */; }; 35D0B7531DDFABFD003EACCD /* MSWrapperLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */; }; 35D0B7541DDFABFD003EACCD /* MSWrapperLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */; }; - 3805DDA71EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */; }; 380A4DCB1DD6908A00E99219 /* MSUtilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */; }; 381C91E91D3DB65D004512F1 /* MSDeviceTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 381C91E51D3DB65D004512F1 /* MSDeviceTracker.h */; }; 382CFCF11EC3817B003FE40B /* MSChannelDefaultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 382CFCF01EC3817B003FE40B /* MSChannelDefaultPrivate.h */; }; @@ -338,7 +333,6 @@ 385FC0551D37EBD700A1799F /* MSDeviceTrackerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */; }; 38641B051EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */; }; 386E8D931E25932100EECF0F /* MSHttpTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 386E8D911E25932100EECF0F /* MSHttpTestUtil.m */; }; - 3872CA981ECA0B04006B2E3B /* MSMockCustomAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3872CA971ECA0B04006B2E3B /* MSMockCustomAppDelegate.m */; }; 387C75811D6270A300D68CC1 /* MSServiceAbstractInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */; }; 387C758F1D64E50800D68CC1 /* MSServiceCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C758D1D64DF2500D68CC1 /* MSServiceCommon.h */; }; 387C75961D64EE1900D68CC1 /* MSServiceAbstractTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 387C75951D64EE1900D68CC1 /* MSServiceAbstractTests.m */; }; @@ -600,8 +594,6 @@ 3592ABA61DC90E3600EF4592 /* MSLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSLogger.m; sourceTree = ""; }; 35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSWrapperLogger.h; sourceTree = ""; }; 35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSWrapperLogger.m; sourceTree = ""; }; - 3805DDA51EB7A5F6001DB846 /* MSMockOriginalAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSMockOriginalAppDelegate.h; sourceTree = ""; }; - 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSMockOriginalAppDelegate.m; sourceTree = ""; }; 380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSUtilityTests.m; sourceTree = ""; }; 381C91E51D3DB65D004512F1 /* MSDeviceTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSDeviceTracker.h; sourceTree = ""; }; 382CFCF01EC3817B003FE40B /* MSChannelDefaultPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSChannelDefaultPrivate.h; sourceTree = ""; }; @@ -623,8 +615,6 @@ 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSAppDelegateForwarderTests.m; sourceTree = ""; }; 386E8D911E25932100EECF0F /* MSHttpTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSHttpTestUtil.m; sourceTree = ""; }; 386E8D921E25932100EECF0F /* MSHttpTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSHttpTestUtil.h; sourceTree = ""; }; - 3872CA961ECA0B04006B2E3B /* MSMockCustomAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSMockCustomAppDelegate.h; sourceTree = ""; }; - 3872CA971ECA0B04006B2E3B /* MSMockCustomAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSMockCustomAppDelegate.m; sourceTree = ""; }; 387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MSServiceAbstractInternal.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 387C758D1D64DF2500D68CC1 /* MSServiceCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MSServiceCommon.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 387C75951D64EE1900D68CC1 /* MSServiceAbstractTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MSServiceAbstractTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; @@ -1128,10 +1118,6 @@ E88D17051D35B6B500A5EA57 /* MSMockLog.m */, D377A30B1E83A04600B2C97A /* MSMockUserDefaults.h */, D377A30C1E83A05900B2C97A /* MSMockUserDefaults.m */, - 3805DDA51EB7A5F6001DB846 /* MSMockOriginalAppDelegate.h */, - 3805DDA61EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m */, - 3872CA961ECA0B04006B2E3B /* MSMockCustomAppDelegate.h */, - 3872CA971ECA0B04006B2E3B /* MSMockCustomAppDelegate.m */, 805F3F691F209C8A00B489E4 /* MSMockService.h */, 805F3F6A1F209C9D00B489E4 /* MSMockService.m */, 04311FEE1EE083C2007054C5 /* MSTestFrameworks.h */, @@ -1749,12 +1735,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0446DF021F3B864600C8E338 /* MSMockOriginalAppDelegate.m in Sources */, 0446DF031F3B864600C8E338 /* MSCustomPropertiesLogTests.m in Sources */, 0446DF041F3B864600C8E338 /* MSMockUserDefaults.m in Sources */, 0446DF051F3B864600C8E338 /* MSLogWithPropertiesTests.m in Sources */, 0446DF061F3B864600C8E338 /* MSDeviceLogTests.m in Sources */, - 0446DF071F3B864600C8E338 /* MSMockCustomAppDelegate.m in Sources */, 0446DF081F3B864600C8E338 /* MSDeviceTrackerTests.m in Sources */, 0446DF091F3B864600C8E338 /* MSAppDelegateForwarderTests.m in Sources */, 0446DF0A1F3B864600C8E338 /* MSChannelDefaultTests.m in Sources */, @@ -1785,7 +1769,6 @@ buildActionMask = 2147483647; files = ( 046AEAD31ECA562A00CBE511 /* MSCustomPropertiesLogTests.m in Sources */, - 04873E881F2FDECE00A13AFF /* MSMockOriginalAppDelegate.m in Sources */, 0446DF321F3B870700C8E338 /* MSDBStorageTests.m in Sources */, 04A140871ECE63BB001CEE94 /* MSServiceAbstractTests.m in Sources */, 0446DF311F3B86FE00C8E338 /* MSStoragePerfomanceTests.m in Sources */, @@ -1802,7 +1785,6 @@ 046AEAE41ECA562A00CBE511 /* MSStartServiceLogTests.m in Sources */, 0446DF331F3B870A00C8E338 /* MSLogDBStorageTests.m in Sources */, 046AEAE61ECA562A00CBE511 /* MSChannelConfigurationTests.m in Sources */, - 04873E891F2FDFD500A13AFF /* MSMockCustomAppDelegate.m in Sources */, 046AEAE81ECA562A00CBE511 /* MSCustomPropertiesTests.m in Sources */, 04A140861ECE60C6001CEE94 /* MSUtilityTests.m in Sources */, 046AEAE91ECA562A00CBE511 /* MSSenderUtilTests.m in Sources */, @@ -1901,12 +1883,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3805DDA71EB7A6A6001DB846 /* MSMockOriginalAppDelegate.m in Sources */, F803BC3A1E8E6963004B1E7A /* MSCustomPropertiesLogTests.m in Sources */, D377A30D1E83A05900B2C97A /* MSMockUserDefaults.m in Sources */, 045660FB1D99EEEB002F7055 /* MSLogWithPropertiesTests.m in Sources */, 6E3E2CC11D3596AE00B1EE50 /* MSDeviceLogTests.m in Sources */, - 3872CA981ECA0B04006B2E3B /* MSMockCustomAppDelegate.m in Sources */, 385FC0551D37EBD700A1799F /* MSDeviceTrackerTests.m in Sources */, 38641B051EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m in Sources */, 6EB1F40E1D2443B7005F9F99 /* MSChannelDefaultTests.m in Sources */, diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index d27d9db3ad..45e7e068c5 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -522,5 +522,13 @@ + (void)flushTraceBuffer { [self.traceBuffer removeAllObjects]; }); } + +#pragma mark - Testing + ++ (void)reset { + [self.delegates removeAllObjects]; + [self.originalImplementations removeAllObjects]; + [self.selectorsToSwizzle removeAllObjects]; +} @end diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h index 781d855c40..056748c1ba 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h @@ -54,6 +54,11 @@ NS_ASSUME_NONNULL_BEGIN */ + (void)swizzleOriginalDelegate:(id)originalDelegate; +/** + * Reset the app delegate forwarder, used for testing only. + */ ++ (void)reset; + @end NS_ASSUME_NONNULL_END diff --git a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m index dfd93cdbd2..8313a3dd67 100644 --- a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m +++ b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m @@ -10,15 +10,11 @@ #endif #import "MSAppDelegateForwarderPrivate.h" -#import "MSMockCustomAppDelegate.h" -#import "MSMockOriginalAppDelegate.h" #import "MSTestFrameworks.h" #import "MSUtility+Application.h" @interface MSAppDelegateForwarderTest : XCTestCase -@property(nonatomic) MSMockOriginalAppDelegate *originalAppDelegateMock; -@property(nonatomic) MSMockCustomAppDelegate *customAppDelegateMock; @property(nonatomic) MSApplication *appMock; @end @@ -37,19 +33,16 @@ @implementation MSAppDelegateForwarderTest - (void)setUp { [super setUp]; + + // The app delegate forwarder is already set via the load method, reset it for testing. + [MSAppDelegateForwarder reset]; // Mock app delegate. self.appMock = OCMClassMock([MSApplication class]); - self.originalAppDelegateMock = [MSMockOriginalAppDelegate new]; - self.customAppDelegateMock = [MSMockCustomAppDelegate new]; - id utilMock = OCMClassMock([MSUtility class]); - OCMStub([utilMock sharedAppDelegate]).andReturn(self.originalAppDelegateMock); } -- (void)tearDown { - - // Clear delegates. - MSAppDelegateForwarder.delegates = [NSHashTable new]; +- (void)tearDown{ + [MSAppDelegateForwarder reset]; [super tearDown]; } @@ -91,8 +84,7 @@ - (void)testSwizzleOriginalPushDelegate { NSError *expectedError = [[NSError alloc] initWithDomain:NSItemProviderErrorDomain code:123 userInfo:@{}]; // App delegate not implementing any selector. - Class originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - id originalAppDelegate = [originalAppDelegateClass new]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; SEL selectorToSwizzle = @selector(application:didFailToRegisterForRemoteNotificationsWithError:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; @@ -113,15 +105,12 @@ - (void)testSwizzleOriginalPushDelegate { */ // App delegate implementing the selector directly. - originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; + originalAppDelegate = [self createOriginalAppDelegateInstance]; __block BOOL wasCalled = NO; id selectorImp = ^{ wasCalled = YES; }; - Method method = class_getInstanceMethod(originalAppDelegateClass, selectorToSwizzle); - const char *types = method_getTypeEncoding(method); - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:originalAppDelegateClass]; - originalAppDelegate = [originalAppDelegateClass new]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -142,11 +131,10 @@ - (void)testSwizzleOriginalPushDelegate { */ // App delegate implementing the selector indirectly. - Class baseClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:baseClass]; - originalAppDelegateClass = [self createClassWithBaseClass:baseClass andConformItToProtocol:nil]; + id originalBaseAppDelegate = [self createOriginalAppDelegateInstance]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalBaseAppDelegate]; + originalAppDelegate = [self createInstanceWithBaseClass:[originalBaseAppDelegate class] andConformItToProtocol:nil]; wasCalled = NO; - originalAppDelegate = [originalAppDelegateClass new]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -172,11 +160,10 @@ - (void)testSwizzleOriginalPushDelegate { id baseSelectorImp = ^{ baseWasCalled = YES; }; - baseClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - [self addSelector:selectorToSwizzle implementation:baseSelectorImp types:types toClass:baseClass]; - originalAppDelegateClass = [self createClassWithBaseClass:baseClass andConformItToProtocol:nil]; - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:originalAppDelegateClass]; - originalAppDelegate = [originalAppDelegateClass new]; + originalBaseAppDelegate = [self createOriginalAppDelegateInstance]; + [self addSelector:selectorToSwizzle implementation:baseSelectorImp toInstance:originalBaseAppDelegate]; + originalAppDelegate = [self createInstanceWithBaseClass:[originalBaseAppDelegate class] andConformItToProtocol:nil]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -198,21 +185,14 @@ - (void)testSwizzleOriginalPushDelegate { */ // App delegate not implementing any selector still responds to selector. - originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; + originalAppDelegate = [self createOriginalAppDelegateInstance]; SEL instancesRespondToSelector = @selector(instancesRespondToSelector:); id instancesRespondToSelectorImp = ^{ return YES; }; - method = class_getClassMethod(originalAppDelegateClass, instancesRespondToSelector); - const char *instancesRespondToSelectorTypes = method_getTypeEncoding(method); - // Adding a class method to a class requires its meta class. - Class originalAppDelegateMetaClass = object_getClass(originalAppDelegateClass); - [self addSelector:instancesRespondToSelector - implementation:instancesRespondToSelectorImp - types:instancesRespondToSelectorTypes - toClass:originalAppDelegateMetaClass]; - originalAppDelegate = [originalAppDelegateClass new]; + // Adding a class method to a class requires its meta class. A meta class is the superclass of a class. + [self addSelector:instancesRespondToSelector implementation:instancesRespondToSelectorImp toClass:object_getClass([originalAppDelegate class])]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -225,10 +205,10 @@ - (void)testSwizzleOriginalPushDelegate { */ // Original delegate still responding to selector. - assertThatBool([originalAppDelegateClass instancesRespondToSelector:selectorToSwizzle], isTrue()); + assertThatBool([[originalAppDelegate class] instancesRespondToSelector:selectorToSwizzle], isTrue()); // Swizzling did not happened so no method added/replaced for this selector. - assertThatBool(class_getInstanceMethod(originalAppDelegateClass, selectorToSwizzle) == NULL, isTrue()); + assertThatBool(class_getInstanceMethod([originalAppDelegate class], selectorToSwizzle) == NULL, isTrue()); } #if !TARGET_OS_OSX @@ -245,8 +225,7 @@ - (void)testSwizzleOriginalOpenURLDelegate { NSDictionary *expectedOptions = @{}; // App delegate not implementing any selector. - Class originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - id originalAppDelegate = [originalAppDelegateClass new]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; SEL selectorToSwizzle = @selector(application:openURL:options:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; @@ -267,16 +246,13 @@ - (void)testSwizzleOriginalOpenURLDelegate { */ // App delegate implementing the selector directly. - originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; + originalAppDelegate = [self createOriginalAppDelegateInstance]; __block BOOL wasCalled = NO; id selectorImp = ^{ wasCalled = YES; return YES; }; - Method method = class_getInstanceMethod(originalAppDelegateClass, selectorToSwizzle); - const char *types = method_getTypeEncoding(method); - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:originalAppDelegateClass]; - originalAppDelegate = [originalAppDelegateClass new]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -297,11 +273,10 @@ - (void)testSwizzleOriginalOpenURLDelegate { */ // App delegate implementing the selector indirectly. - Class baseClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:baseClass]; - originalAppDelegateClass = [self createClassWithBaseClass:baseClass andConformItToProtocol:nil]; + id originalBaseAppDelegate = [self createOriginalAppDelegateInstance]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalBaseAppDelegate]; + originalAppDelegate = [self createInstanceWithBaseClass:[originalBaseAppDelegate class] andConformItToProtocol:nil]; wasCalled = NO; - originalAppDelegate = [originalAppDelegateClass new]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -327,11 +302,10 @@ - (void)testSwizzleOriginalOpenURLDelegate { id baseSelectorImp = ^{ baseWasCalled = YES; }; - baseClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - [self addSelector:selectorToSwizzle implementation:baseSelectorImp types:types toClass:baseClass]; - originalAppDelegateClass = [self createClassWithBaseClass:baseClass andConformItToProtocol:nil]; - [self addSelector:selectorToSwizzle implementation:selectorImp types:types toClass:originalAppDelegateClass]; - originalAppDelegate = [originalAppDelegateClass new]; + originalBaseAppDelegate = [self createOriginalAppDelegateInstance]; + [self addSelector:selectorToSwizzle implementation:baseSelectorImp toInstance:originalBaseAppDelegate]; + originalAppDelegate = [self createInstanceWithBaseClass:[originalBaseAppDelegate class] andConformItToProtocol:nil]; + [self addSelector:selectorToSwizzle implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -353,21 +327,14 @@ - (void)testSwizzleOriginalOpenURLDelegate { */ // App delegate not implementing any selector still responds to selector. - originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; + originalAppDelegate = [self createOriginalAppDelegateInstance]; SEL instancesRespondToSelector = @selector(instancesRespondToSelector:); id instancesRespondToSelectorImp = ^{ return YES; }; - method = class_getClassMethod(originalAppDelegateClass, instancesRespondToSelector); - const char *instancesRespondToSelectorTypes = method_getTypeEncoding(method); // Adding a class method to a class requires its meta class. - Class originalAppDelegateMetaClass = object_getClass(originalAppDelegateClass); - [self addSelector:instancesRespondToSelector - implementation:instancesRespondToSelectorImp - types:instancesRespondToSelectorTypes - toClass:originalAppDelegateMetaClass]; - originalAppDelegate = [originalAppDelegateClass new]; + [self addSelector:instancesRespondToSelector implementation:instancesRespondToSelectorImp toClass:object_getClass([originalAppDelegate class])]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -380,10 +347,10 @@ - (void)testSwizzleOriginalOpenURLDelegate { */ // Original delegate still responding to selector. - assertThatBool([originalAppDelegateClass instancesRespondToSelector:selectorToSwizzle], isTrue()); + assertThatBool([[originalAppDelegate class] instancesRespondToSelector:selectorToSwizzle], isTrue()); // Swizzling did not happened so no method added/replaced for this selector. - assertThatBool(class_getInstanceMethod(originalAppDelegateClass, selectorToSwizzle) == NULL, isTrue()); + assertThatBool(class_getInstanceMethod([originalAppDelegate class], selectorToSwizzle) == NULL, isTrue()); } #endif @@ -419,29 +386,29 @@ - (void)testWithoutCustomDelegate { // If NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; - NSDictionary *expectedAnnotation = @{}; + NSDictionary *expectedOptions = @{}; BOOL expectedReturnedValue = YES; MSApplication *appMock = self.appMock; XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; - SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { + SEL originalOpenURLSel = @selector(application:openURL:options:); + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLSel]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { // Then assertThat(application, is(appMock)); assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); + assertThat(options, is(expectedOptions)); [originalCalledExpectation fulfill]; return expectedReturnedValue; }; + [self addSelector:originalOpenURLSel implementation:originalOpenURLImp toInstance:originalAppDelegate]; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + options:expectedOptions]; // Then assertThatUnsignedLong(MSAppDelegateForwarder.delegates.count, equalToUnsignedLong(0)); @@ -459,18 +426,19 @@ - (void)testWithoutCustomDelegateNotReturningValue { SEL originalDidRegisterForRemoteNotificationsWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationsWithDeviceTokenSel]; - self.originalAppDelegateMock - .delegateValidators[NSStringFromSelector(originalDidRegisterForRemoteNotificationsWithDeviceTokenSel)] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidRegisterForRemoteNotificationsWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationsWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationsWithDeviceTokenImp toInstance:originalAppDelegate]; // When - [self.originalAppDelegateMock application:self.appMock + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then @@ -483,45 +451,46 @@ - (void)testWithOneCustomDelegate { // If NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; - NSDictionary *expectedAnnotation = @{}; + NSDictionary *expectedOptions = @{}; BOOL expectedReturnedValue = YES; MSApplication *appMock = self.appMock; XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; - SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { + SEL originalOpenURLiOS90Sel = @selector(application:openURL:options:); + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS90Sel]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLiOS90Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; + [self addSelector:originalOpenURLiOS90Sel implementation:originalOpenURLiOS90Imp toInstance:originalAppDelegate]; + SEL customOpenURLiOS90Sel = @selector(application:openURL:options:returnedValue:); + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customOpenURLiOS90Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { // Then assertThat(application, is(appMock)); assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; - NSString *customOpenURLiOS42Str = - NSStringFromSelector(@selector(application:openURL:sourceApplication:annotation:returnedValue:)); - self.customAppDelegateMock.delegateValidators[customOpenURLiOS42Str] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); + assertThat(options, is(expectedOptions)); assertThatBool(returnedValue, is(@(expectedReturnedValue))); [customCalledExpectation fulfill]; return expectedReturnedValue; }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + [self addSelector:customOpenURLiOS90Sel implementation:customOpenURLiOS90Imp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + options:expectedOptions]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -537,28 +506,32 @@ - (void)testWithOneCustomDelegateNotReturningValue { XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; SEL didRegisterNotificationSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); - NSString *didRegisterNotificationStr = NSStringFromSelector(didRegisterNotificationSel); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didRegisterNotificationSel]; - self.originalAppDelegateMock.delegateValidators[didRegisterNotificationStr] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - self.customAppDelegateMock.delegateValidators[didRegisterNotificationStr] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation fulfill]; - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidRegisterNotificationImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:didRegisterNotificationSel implementation:originalDidRegisterNotificationImp toInstance:originalAppDelegate]; + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customDidRegisterNotificationImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation fulfill]; + }; + [self addSelector:didRegisterNotificationSel implementation:customDidRegisterNotificationImp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - [self.originalAppDelegateMock application:appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; + [originalAppDelegate application:appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then [self waitForExpectations:@[ originalCalledExpectation, customCalledExpectation ] timeout:1]; @@ -575,32 +548,35 @@ - (void)testDontForwardSelectorsNotToOverrideIfAlreadyImplementedByOriginalDeleg MSApplication *appMock = self.appMock; XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; SEL didReceiveRemoteNotificationSel = @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:); - NSString *didReceiveRemoteNotificationStr = NSStringFromSelector(didReceiveRemoteNotificationSel); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotificationSel]; - self.originalAppDelegateMock.delegateValidators[didReceiveRemoteNotificationStr] = - ^(MSApplication *application, NSDictionary *userInfo, void (^completionHandler)(UIBackgroundFetchResult result)) { - - // Then - assertThat(application, is(appMock)); - assertThat(userInfo, is(expectedUserInfo)); - assertThat(completionHandler, is(expectedCompletionHandler)); - [originalCalledExpectation fulfill]; - }; - self.customAppDelegateMock.delegateValidators[didReceiveRemoteNotificationStr] = - ^(__attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"This method is already implemented in the original delegate and is marked not to be swizzled."); - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidReceiveRemoteNotificationImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo, void (^completionHandler)(UIBackgroundFetchResult result)) { + + // Then + assertThat(application, is(appMock)); + assertThat(userInfo, is(expectedUserInfo)); + assertThat(completionHandler, is(expectedCompletionHandler)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:didReceiveRemoteNotificationSel implementation:originalDidReceiveRemoteNotificationImp toInstance:originalAppDelegate]; + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customDidReceiveRemoteNotificationImp = + ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"This method is already implemented in the original delegate and is marked not to be swizzled."); + }; + [self addSelector:didReceiveRemoteNotificationSel implementation:customDidReceiveRemoteNotificationImp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; // When - [self.originalAppDelegateMock application:appMock + [originalAppDelegate application:appMock didReceiveRemoteNotification:expectedUserInfo fetchCompletionHandler:expectedCompletionHandler]; // Then - assertThatBool([MSAppDelegateForwarder.selectorsNotToOverride containsObject:didReceiveRemoteNotificationStr], + assertThatBool([MSAppDelegateForwarder.selectorsNotToOverride containsObject:NSStringFromSelector(didReceiveRemoteNotificationSel)], isTrue()); [self waitForExpectations:@[ originalCalledExpectation ] timeout:1]; } @@ -611,61 +587,61 @@ - (void)testWithMultipleCustomOpenURLDelegates { // If NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; - NSDictionary *expectedAnnotation = @{}; + NSDictionary *expectedOptions = @{}; BOOL expectedReturnedValue = YES; XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; XCTestExpectation *customCalledExpectation1 = [self expectationWithDescription:@"Custom delegate 1 called."]; XCTestExpectation *customCalledExpectation2 = [self expectationWithDescription:@"Custom delegate 2 called."]; MSApplication *appMock = self.appMock; - SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; - MSMockCustomAppDelegate *customAppDelegateMock1 = [MSMockCustomAppDelegate new]; - NSString *customOpenURLiOS42Str = - NSStringFromSelector(@selector(application:openURL:sourceApplication:annotation:returnedValue:)); - customAppDelegateMock1.delegateValidators[customOpenURLiOS42Str] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - [customCalledExpectation1 fulfill]; - return expectedReturnedValue; - }; - MSMockCustomAppDelegate *customAppDelegateMock2 = [MSMockCustomAppDelegate new]; - customAppDelegateMock2.delegateValidators[customOpenURLiOS42Str] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - [customCalledExpectation2 fulfill]; - return expectedReturnedValue; - }; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock1]; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock2]; + SEL originalOpenURLiOS90Sel = @selector(application:openURL:options:); + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS90Sel]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLiOS90Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; + [self addSelector:originalOpenURLiOS90Sel implementation:originalOpenURLiOS90Imp toInstance:originalAppDelegate]; + SEL customOpenURLiOS90Sel = @selector(application:openURL:options:returnedValue:); + id customAppDelegate1 = [self createCustomAppDelegateInstance]; + id customOpenURLiOS90Imp1 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + [customCalledExpectation1 fulfill]; + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS90Sel implementation:customOpenURLiOS90Imp1 toInstance:customAppDelegate1]; + id customAppDelegate2 = [self createCustomAppDelegateInstance]; + id customOpenURLiOS90Imp2 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + [customCalledExpectation2 fulfill]; + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS90Sel implementation:customOpenURLiOS90Imp2 toInstance:customAppDelegate2]; + [MSAppDelegateForwarder addDelegate:customAppDelegate1]; + [MSAppDelegateForwarder addDelegate:customAppDelegate2]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + options:expectedOptions]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -685,40 +661,43 @@ - (void)testWithMultipleCustomPushDelegates { SEL originalDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; - self.originalAppDelegateMock - .delegateValidators[NSStringFromSelector(originalDidRegisterForRemoteNotificationWithDeviceTokenSel)] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - MSMockCustomAppDelegate *customAppDelegateMock1 = [MSMockCustomAppDelegate new]; - NSString *customDidRegisterForRemoteNotificationWithDeviceTokenStr = - NSStringFromSelector(@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)); - customAppDelegateMock1.delegateValidators[customDidRegisterForRemoteNotificationWithDeviceTokenStr] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation1 fulfill]; - }; - MSMockCustomAppDelegate *customAppDelegateMock2 = [MSMockCustomAppDelegate new]; - customAppDelegateMock2.delegateValidators[customDidRegisterForRemoteNotificationWithDeviceTokenStr] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation2 fulfill]; - }; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock1]; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock2]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + id customAppDelegate1 = [self createCustomAppDelegateInstance]; + id customDidRegisterForRemoteNotificationWithDeviceTokenImp1 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation1 fulfill]; + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp1 toInstance:customAppDelegate1]; + id customAppDelegate2 = [self createCustomAppDelegateInstance]; + id customDidRegisterForRemoteNotificationWithDeviceTokenImp2 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation2 fulfill]; + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp2 toInstance:customAppDelegate2]; + [MSAppDelegateForwarder addDelegate:customAppDelegate1]; + [MSAppDelegateForwarder addDelegate:customAppDelegate2]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - [self.originalAppDelegateMock application:self.appMock + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then @@ -737,33 +716,36 @@ - (void)testWithRemovedCustomOpenURLDelegate { XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; - NSString *customOpenURLiOS42Str = - NSStringFromSelector(@selector(application:openURL:sourceApplication:annotation:returnedValue:)); - self.customAppDelegateMock.delegateValidators[customOpenURLiOS42Str] = - ^(__attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, - __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, - __attribute__((unused)) BOOL returnedValue) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - return expectedReturnedValue; - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; - [MSAppDelegateForwarder removeDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLiOS42Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; + [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; + SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customOpenURLiOS42Imp = + ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, + __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, + __attribute__((unused)) BOOL returnedValue) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; + [MSAppDelegateForwarder removeDelegate:customAppDelegate]; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnnotation]; @@ -783,28 +765,30 @@ - (void)testWithRemovedCustomDidRegisterForRemoteNotificationWithDeviceTokenDele SEL originalDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; - self.originalAppDelegateMock - .delegateValidators[NSStringFromSelector(originalDidRegisterForRemoteNotificationWithDeviceTokenSel)] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - NSString *customDidRegisterForRemoteNotificationWithDeviceTokenStr = - NSStringFromSelector(@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)); - self.customAppDelegateMock.delegateValidators[customDidRegisterForRemoteNotificationWithDeviceTokenStr] = - ^(__attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; - [MSAppDelegateForwarder removeDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customDidRegisterForRemoteNotificationWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; + [MSAppDelegateForwarder removeDelegate:customAppDelegate]; // When - [self.originalAppDelegateMock application:self.appMock + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then @@ -822,33 +806,36 @@ - (void)testDontForwardOpenURLOnDisable { XCTestExpectation *originalCalledExpectation = [self expectationWithDescription:@"Original delegate called."]; SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; - NSString *customOpenURLiOS42Str = - NSStringFromSelector(@selector(application:openURL:sourceApplication:annotation:returnedValue:)); - self.customAppDelegateMock.delegateValidators[customOpenURLiOS42Str] = - ^(__attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, - __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, - __attribute__((unused)) BOOL returnedValue) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - return expectedReturnedValue; - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLiOS42Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; + [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; + SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customOpenURLiOS42Imp = + ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, + __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, + __attribute__((unused)) BOOL returnedValue) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; MSAppDelegateForwarder.enabled = NO; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnnotation]; @@ -869,28 +856,30 @@ - (void)testDontForwardDidRegisterForRemoteNotificationWithDeviceTokenOnDisable SEL originalDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; - self.originalAppDelegateMock - .delegateValidators[NSStringFromSelector(originalDidRegisterForRemoteNotificationWithDeviceTokenSel)] = - ^(MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - NSString *customDidRegisterForRemoteNotificationWithDeviceTokenStr = - NSStringFromSelector(@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)); - self.customAppDelegateMock.delegateValidators[customDidRegisterForRemoteNotificationWithDeviceTokenStr] = - ^(__attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + id customAppDelegate = [self createCustomAppDelegateInstance]; + id customDidRegisterForRemoteNotificationWithDeviceTokenImp = + ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; MSAppDelegateForwarder.enabled = NO; // When - [self.originalAppDelegateMock application:self.appMock + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then @@ -912,53 +901,57 @@ - (void)testReturnValueChaining { MSApplication *appMock = self.appMock; SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; - self.originalAppDelegateMock.delegateValidators[NSStringFromSelector(originalOpenURLiOS42Sel)] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - expectedReturnedValue = initialReturnValue; - return expectedReturnedValue; - }; - MSMockCustomAppDelegate *customAppDelegateMock1 = [MSMockCustomAppDelegate new]; - MSMockCustomAppDelegate *customAppDelegateMock2 = [MSMockCustomAppDelegate new]; - NSString *customOpenURLiOS42Str = - NSStringFromSelector(@selector(application:openURL:sourceApplication:annotation:returnedValue:)); - customAppDelegateMock1.delegateValidators[customOpenURLiOS42Str] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - expectedReturnedValue = !returnedValue; - [customCalledExpectation1 fulfill]; - return expectedReturnedValue; - }; - customAppDelegateMock2.delegateValidators[customOpenURLiOS42Str] = - ^(MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - expectedReturnedValue = !returnedValue; - [customCalledExpectation2 fulfill]; - return expectedReturnedValue; - }; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock1]; - [MSAppDelegateForwarder addDelegate:customAppDelegateMock2]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id originalOpenURLiOS42Imp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + expectedReturnedValue = initialReturnValue; + return expectedReturnedValue; + }; + [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; + SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); + id customAppDelegate1 = [self createCustomAppDelegateInstance]; + id customOpenURLiOS42Imp1 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + expectedReturnedValue = !returnedValue; + [customCalledExpectation1 fulfill]; + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp1 toInstance:customAppDelegate1]; + id customAppDelegate2 = [self createCustomAppDelegateInstance]; + id customOpenURLiOS42Imp2 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + expectedReturnedValue = !returnedValue; + [customCalledExpectation2 fulfill]; + return expectedReturnedValue; + }; + [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp2 toInstance:customAppDelegate2]; + [MSAppDelegateForwarder addDelegate:customAppDelegate1]; + [MSAppDelegateForwarder addDelegate:customAppDelegate2]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = [self.originalAppDelegateMock application:self.appMock + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnnotation]; @@ -974,34 +967,30 @@ - (void)testReturnValueChaining { - (void)testOpenURLForwardMethodNotImplementedByOriginalDelegate { // If - NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; - NSDictionary *expectedOptions = @{}; - BOOL expectedReturnedValue = NO; + NSError *expectedError = [NSError errorWithDomain:@"Don't worry, not a real error." code:404 userInfo:nil]; MSApplication *appMock = self.appMock; XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; - SEL originalOpenURLiOS9Sel = @selector(application:openURL:options:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS9Sel]; - NSString *customOpenURLiOS9Str = NSStringFromSelector(@selector(application:openURL:options:returnedValue:)); - self.customAppDelegateMock.delegateValidators[customOpenURLiOS9Str] = - ^(MSApplication *application, NSURL *url, NSDictionary *options, - BOOL returnedValue) { + SEL didFailToRegisterForNotifSel = @selector(application:didFailToRegisterForRemoteNotificationsWithError:); + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didFailToRegisterForNotifSel]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + id customAppDelegate = [self createCustomAppDelegateInstance]; + id didFailToRegisterForNotifImp = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSError *error) { + + // Then + assertThat(application, is(appMock)); + assertThat(error, is(expectedError)); + [customCalledExpectation fulfill]; + }; - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - [customCalledExpectation fulfill]; - return expectedReturnedValue; - }; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + [self addSelector:didFailToRegisterForNotifSel implementation:didFailToRegisterForNotifImp toInstance:customAppDelegate]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = - [self.originalAppDelegateMock application:self.appMock openURL:expectedURL options:expectedOptions]; + [originalAppDelegate application:self.appMock didFailToRegisterForRemoteNotificationsWithError:expectedError]; // Then - assertThatBool(returnedValue, is(@(expectedReturnedValue))); [self waitForExpectations:@[ customCalledExpectation ] timeout:1]; } #endif @@ -1019,13 +1008,14 @@ - (void)testDidReceiveNotification { XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; // Setup an empty original delegate. - Class originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; + Class originalAppDelegateClass = [self createInstanceConformingToProtocol:@protocol(MSApplicationDelegate)]; id originalAppDelegate = [originalAppDelegateClass new]; SEL applicationDidFinishLaunchingSel = @selector(applicationDidFinishLaunching:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:applicationDidFinishLaunchingSel]; // Setup a custom delegate. - self.customAppDelegateMock.delegateValidators[NSStringFromSelector(applicationDidFinishLaunchingSel)] = + id customAppDelegate = [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; + id applicationDidFinishLaunchingImp = ^(NSNotification *notification) { // Then @@ -1036,8 +1026,9 @@ - (void)testDidReceiveNotification { assertThat(userNotification.userInfo, is(expectedUserInfo)); [customCalledExpectation fulfill]; }; + [self addSelector:applicationDidFinishLaunchingSel implementation:applicationDidFinishLaunchingImp toInstance:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; // When [originalAppDelegate applicationDidFinishLaunching:notificationMock]; @@ -1064,37 +1055,39 @@ - (void)testDidReceiveRemoteNotification { XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; // Setup an empty original delegate. - Class originalAppDelegateClass = [self createClassConformingToProtocol:@protocol(MSApplicationDelegate)]; - id originalAppDelegate = [originalAppDelegateClass new]; - SEL didReceiveRemoteNotification1Sel = @selector(application:didReceiveRemoteNotification:); - SEL didReceiveRemoteNotification2Sel = @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotification1Sel]; - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotification2Sel]; + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + SEL didReceiveRemoteNotificationSel1 = @selector(application:didReceiveRemoteNotification:); + SEL didReceiveRemoteNotificationSel2 = @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:); + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotificationSel1]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotificationSel2]; // Setup a custom delegate. - self.customAppDelegateMock.delegateValidators[NSStringFromSelector(didReceiveRemoteNotification1Sel)] = - ^(MSApplication *application, NSDictionary *userInfo) { - - // Then - assertThat(application, is(appMock)); - assertThat(userInfo, is(expectedUserInfo)); - }; - self.customAppDelegateMock.delegateValidators[NSStringFromSelector(didReceiveRemoteNotification2Sel)] = - ^(MSApplication *application, NSDictionary *userInfo, void (^fetchHandler)(UIBackgroundFetchResult)) { - - // Then - assertThat(application, is(appMock)); - assertThat(userInfo, is(expectedUserInfo)); - assertThat(fetchHandler, is(fetchHandler)); - - // The original handler must only be called after all delegate did run. - assertThatBool(isOriginalHandlerCalled, isFalse()); - fetchHandler(expectedFetchResult); - assertThatBool(isOriginalHandlerCalled, isFalse()); - [customCalledExpectation fulfill]; - }; + id customAppDelegate = [self createCustomAppDelegateInstance]; + id didReceiveRemoteNotificationImp1 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo) { + + // Then + assertThat(application, is(appMock)); + assertThat(userInfo, is(expectedUserInfo)); + }; + [self addSelector:didReceiveRemoteNotificationSel1 implementation:didReceiveRemoteNotificationImp1 toInstance:customAppDelegate]; + id didReceiveRemoteNotificationImp2 = + ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo, void (^fetchHandler)(UIBackgroundFetchResult)) { + + // Then + assertThat(application, is(appMock)); + assertThat(userInfo, is(expectedUserInfo)); + assertThat(fetchHandler, is(fetchHandler)); + + // The original handler must only be called after all delegate did run. + assertThatBool(isOriginalHandlerCalled, isFalse()); + fetchHandler(expectedFetchResult); + assertThatBool(isOriginalHandlerCalled, isFalse()); + [customCalledExpectation fulfill]; + }; + [self addSelector:didReceiveRemoteNotificationSel2 implementation:didReceiveRemoteNotificationImp2 toInstance:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; - [MSAppDelegateForwarder addDelegate:self.customAppDelegateMock]; + [MSAppDelegateForwarder addDelegate:customAppDelegate]; // When [originalAppDelegate application:appMock didReceiveRemoteNotification:expectedUserInfo]; @@ -1109,6 +1102,179 @@ - (void)testDidReceiveRemoteNotification { assertThatBool(isOriginalHandlerCalled, isTrue()); assertThatInteger(forwardedFetchResult, equalToInteger(expectedFetchResult)); } + +#endif + +#if !TARGET_OS_OSX + +- (void)testDontSwizzleDeprecatedAPIIfNoAPIImplemented { + + /* + * If + */ + + // Mock a custom app delegate. + id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); + [MSAppDelegateForwarder addDelegate:customDelegate]; + NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; + id expectedOptions = @{}; + OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:NO]); + + // App delegate not implementing any API. + SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); + SEL newSelector = @selector(application:openURL:options:); + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; + + /* + * When + */ + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; + [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; + + /* + * Then + */ + assertThatBool([originalAppDelegate respondsToSelector:newSelector], isTrue()); + assertThatBool([originalAppDelegate respondsToSelector:deprecatedSelector], isFalse()); + OCMVerify([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:NO]); +} + +- (void)testSwizzleDeprecatedAPIIfNoNewAPIImplemented { + + /* + * If + */ + + // Mock a custom app delegate. + id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); + [MSAppDelegateForwarder addDelegate:customDelegate]; + NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; + id expectedAnotation = @{}; + OCMExpect([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); + + // App delegate implementing just the deprecated API. + SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); + SEL newSelector = @selector(application:openURL:options:); + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + __block short nbCalls = 0; + id selectorImp = ^{ + nbCalls ++; + return YES; + }; + [self addSelector:deprecatedSelector implementation:selectorImp toInstance:originalAppDelegate]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; + + /* + * When + */ + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; + [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation]; + + /* + * Then + */ + assertThatBool([originalAppDelegate respondsToSelector:newSelector], isFalse()); + assertThatBool([originalAppDelegate respondsToSelector:deprecatedSelector], isTrue()); + assertThatShort(nbCalls, equalToShort(1)); + OCMVerify([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); +} + +- (void)testSwizzleDeprecatedAPIIfJustNewAPIImplemented { + + /* + * If + */ + + // Mock a custom app delegate. + id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); + [MSAppDelegateForwarder addDelegate:customDelegate]; + NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; + id expectedOptions = @{}; + OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); + + // App delegate implementing just the new API. + SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); + SEL newSelector = @selector(application:openURL:options:); + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + __block short nbCalls = 0; + id selectorImp = ^{ + nbCalls ++; + return YES; + }; + [self addSelector:newSelector implementation:selectorImp toInstance:originalAppDelegate]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; + + /* + * When + */ + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; + [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; + + /* + * Then + */ + assertThatBool([originalAppDelegate respondsToSelector:deprecatedSelector], isFalse()); + assertThatBool([originalAppDelegate respondsToSelector:newSelector], isTrue()); + assertThatShort(nbCalls, equalToShort(1)); + OCMVerify([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); +} + +- (void)testSwizzleDeprecatedAPIIfAllAPIsImplemented { + + /* + * If + */ + + // Mock a custom app delegate. + id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); + [MSAppDelegateForwarder addDelegate:customDelegate]; + NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; + id expectedAnotation = @{}; + id expectedOptions = @{}; + OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); + OCMExpect([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); + + // App delegate implementing all the APIs. + SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); + SEL newSelector = @selector(application:openURL:options:); + id originalAppDelegate = [self createOriginalAppDelegateInstance]; + __block short deprecatedSelectorNbCalls = 0; + __block short newSelectorNbCalls = 0; + id deprecatedSelectorImp = ^{ + deprecatedSelectorNbCalls ++; + return YES; + }; + id newSelectorImp = ^{ + newSelectorNbCalls ++; + return YES; + }; + [self addSelector:deprecatedSelector implementation:deprecatedSelectorImp toInstance:originalAppDelegate]; + [self addSelector:newSelector implementation:newSelectorImp toInstance:originalAppDelegate]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; + [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; + + /* + * When + */ + [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; + [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation]; + [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; + + /* + * Then + */ + assertThatBool([originalAppDelegate respondsToSelector:newSelector], isTrue()); + assertThatBool([originalAppDelegate respondsToSelector:deprecatedSelector], isTrue()); + assertThatShort(newSelectorNbCalls, equalToShort(1)); + assertThatShort(deprecatedSelectorNbCalls, equalToShort(1)); + OCMVerify([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); + OCMVerify([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); +} + #endif #pragma mark - Private @@ -1117,11 +1283,11 @@ - (NSString *)generateClassName { return [@"C" stringByAppendingString:MS_UUID_STRING]; } -- (Class)createClassConformingToProtocol:(Protocol *)protocol { - return [self createClassWithBaseClass:[NSObject class] andConformItToProtocol:protocol]; +- (id)createInstanceConformingToProtocol:(Protocol *)protocol { + return [self createInstanceWithBaseClass:[NSObject class] andConformItToProtocol:protocol]; } -- (Class)createClassWithBaseClass:(Class) class andConformItToProtocol:(Protocol *)protocol { +- (id)createInstanceWithBaseClass:(Class) class andConformItToProtocol:(Protocol *)protocol { // Generate class name to prevent conflicts in runtime added classes. const char *name = [[self generateClassName] UTF8String]; @@ -1130,10 +1296,24 @@ - (Class)createClassWithBaseClass:(Class) class andConformItToProtocol:(Protocol class_addProtocol(newClass, protocol); } objc_registerClassPair(newClass); - return newClass; + return [newClass new]; +} + +- (id)createOriginalAppDelegateInstance{ + return [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; +} + +- (id)createCustomAppDelegateInstance{ + return [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; +} + +- (void)addSelector:(SEL)selector implementation:(id)block toInstance:(id)instance { + [self addSelector:selector implementation:block toClass:[instance class]]; } -- (void)addSelector : (SEL)selector implementation : (id)block types : (const char *)types toClass : (Class) class { +- (void)addSelector:(SEL)selector implementation:(id)block toClass:(id)class { + Method method = class_getInstanceMethod(class, selector); + const char *types = method_getTypeEncoding(method); IMP imp = imp_implementationWithBlock(block); class_addMethod(class, selector, imp, types); } diff --git a/MobileCenter/MobileCenterTests/MSMobileCenterTests.m b/MobileCenter/MobileCenterTests/MSMobileCenterTests.m index c09a8feacc..e2ac91a5e5 100644 --- a/MobileCenter/MobileCenterTests/MSMobileCenterTests.m +++ b/MobileCenter/MobileCenterTests/MSMobileCenterTests.m @@ -5,8 +5,6 @@ #import "MSMobileCenterInternal.h" #import "MSMobileCenterPrivate.h" #import "MSMockService.h" -#import "MSMockCustomAppDelegate.h" -#import "MSMockOriginalAppDelegate.h" #import "MSMockUserDefaults.h" #import "MSStartServiceLog.h" #import "MSTestFrameworks.h" diff --git a/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.h b/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.h deleted file mode 100644 index 3a722a4256..0000000000 --- a/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.h +++ /dev/null @@ -1,32 +0,0 @@ -#import -#if TARGET_OS_OSX -#import -#import "MSNSAppDelegate.h" -#else -#import -#import "MSUIAppDelegate.h" -#endif - -#if TARGET_OS_OSX -typedef BOOL (^CustomDidRegisterNotificationValidator)(NSApplication *, NSData *); -typedef BOOL (^CustomDidFinishLaunchingValidator)(NSNotification *); -#else -typedef BOOL (^CustomOpenURLiOS42Validator)(UIApplication *, NSURL *, NSString *, id, BOOL); -typedef BOOL (^CustomOpenURLiOS9Validator)(UIApplication *, NSURL *, NSDictionary *, - BOOL); -typedef BOOL (^CustomDidRegisterNotificationValidator)(UIApplication *, NSData *); -typedef BOOL (^CustomDidReceiveNotificationWorkaroundValidator)(UIApplication *application, NSDictionary *userInfo); -typedef BOOL (^CustomDidReceiveNotificationValidator)(UIApplication *application, NSDictionary *userInfo, - void (^fetchHandler)(UIBackgroundFetchResult)); -#endif - -/* - * We Can't use OCMock to mock original app delegate since the class needs to own the method implementation. - * We also can't use OCMock's protocol mocks since they artificially responds to any selector from the protocol. - * Adding this class that can be used for both custom and original delegate to solve the issue for some tests. - */ -@interface MSMockCustomAppDelegate : NSObject - -@property(nonatomic, readonly) NSMutableDictionary *delegateValidators; - -@end diff --git a/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.m b/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.m deleted file mode 100644 index 4e7008cdfe..0000000000 --- a/MobileCenter/MobileCenterTests/Util/MSMockCustomAppDelegate.m +++ /dev/null @@ -1,86 +0,0 @@ -#import - -#import "MSAppDelegateForwarder.h" -#import "MSMockCustomAppDelegate.h" - -@implementation MSMockCustomAppDelegate - -- (instancetype)init { - if ((self = [super init])) { - _delegateValidators = [NSMutableDictionary new]; - } - return self; -} - -#pragma mark - MSAppDelegate - -#if TARGET_OS_OSX - -- (void)application:(NSApplication *)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - CustomDidRegisterNotificationValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, deviceToken); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification { - CustomDidFinishLaunchingValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(notification); -} - -#else -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation - returnedValue:(BOOL)returnedValue { - CustomOpenURLiOS42Validator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - return validator(application, url, sourceApplication, annotation, returnedValue); -} - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - options:(NSDictionary *)options - returnedValue:(BOOL)returnedValue { - CustomOpenURLiOS9Validator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - return validator(application, url, options, returnedValue); -} - -- (void)application:(UIApplication *)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - CustomDidRegisterNotificationValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, deviceToken); -} - -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { - CustomDidReceiveNotificationWorkaroundValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, userInfo); -} - -- (void)application:(UIApplication *)application - didReceiveRemoteNotification:(NSDictionary *)userInfo - fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { - CustomDidReceiveNotificationValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, userInfo, completionHandler); -} -#endif - -@end - -#pragma mark - Swizzling - -@implementation MSAppDelegateForwarder (MSDistribute) - -+ (void)load { - - // Register selectors to swizzle for this mock. - [self addAppDelegateSelectorToSwizzle:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)]; - -#if !TARGET_OS_OSX - [self addAppDelegateSelectorToSwizzle:@selector(application:openURL:options:)]; - [self addAppDelegateSelectorToSwizzle:@selector(application:openURL:sourceApplication:annotation:)]; - [self addAppDelegateSelectorToSwizzle:@selector(application:didReceiveRemoteNotification:)]; - [self addAppDelegateSelectorToSwizzle:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]; -#endif -} - -@end diff --git a/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.h b/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.h deleted file mode 100644 index 63c8d2309c..0000000000 --- a/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.h +++ /dev/null @@ -1,26 +0,0 @@ -#import -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#if TARGET_OS_OSX -typedef BOOL (^OriginalDidRegisterNotificationValidator)(NSApplication *, NSData *); -typedef BOOL (^OriginalDidFinishLaunchingValidator)(NSNotification *); -#else -typedef BOOL (^OriginalOpenURLiOS42Validator)(UIApplication *, NSURL *, NSString *, id); -typedef BOOL (^OriginalDidRegisterNotificationValidator)(UIApplication *, NSData *); -typedef BOOL (^OriginalDidReceiveNotification)(UIApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult)); -#endif - -/* - * We Can't use OCMock to mock original app delegate since the class needs to own the method implementation. - * We also can't use OCMock's protocol mocks since they artificially responds to any selector from the protocol. - * Adding this class that can be used for both custom and original delegate to solve the issue for some tests. - */ -@interface MSMockOriginalAppDelegate : NSObject - -@property(nonatomic, readonly) NSMutableDictionary *delegateValidators; - -@end diff --git a/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.m b/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.m deleted file mode 100644 index 7f4b43e40a..0000000000 --- a/MobileCenter/MobileCenterTests/Util/MSMockOriginalAppDelegate.m +++ /dev/null @@ -1,63 +0,0 @@ -#import - -#import "MSAppDelegateForwarder.h" -#import "MSMockOriginalAppDelegate.h" -#import "MSAppDelegateForwarderPrivate.h" - -@implementation MSMockOriginalAppDelegate - -- (instancetype)init { - if ((self = [super init])) { - _delegateValidators = [NSMutableDictionary new]; - - // Force swizzling for tests. - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [MSAppDelegateForwarder swizzleOriginalDelegate:self]; - }); - } - return self; -} - -#if TARGET_OS_OSX - -#pragma mark - NSApplication - -- (void)application:(NSApplication *)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - OriginalDidRegisterNotificationValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, deviceToken); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification { - OriginalDidFinishLaunchingValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(notification); -} - -#else - -#pragma mark - UIApplication - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - OriginalOpenURLiOS42Validator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - return validator(application, url, sourceApplication, annotation); -} - -- (void)application:(UIApplication *)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - OriginalDidRegisterNotificationValidator validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, deviceToken); -} - -- (void)application:(UIApplication *)application - didReceiveRemoteNotification:(NSDictionary *)userInfo - fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { - OriginalDidReceiveNotification validator = self.delegateValidators[NSStringFromSelector(_cmd)]; - validator(application, userInfo, completionHandler); -} -#endif - -@end From d4c73fc03aaf6e953ea737c29e43aef5b735fb23 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Tue, 5 Sep 2017 09:36:12 -0700 Subject: [PATCH 14/55] Fix formatting + macOS and tvOS tests --- .../AppDelegate/MSAppDelegateForwarder.m | 2 +- .../MSAppDelegateForwarderTests.m | 632 ++++++++++-------- 2 files changed, 337 insertions(+), 297 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 45e7e068c5..49445a5c9d 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -522,7 +522,7 @@ + (void)flushTraceBuffer { [self.traceBuffer removeAllObjects]; }); } - + #pragma mark - Testing + (void)reset { diff --git a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m index 8313a3dd67..4034969d3a 100644 --- a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m +++ b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m @@ -33,7 +33,7 @@ @implementation MSAppDelegateForwarderTest - (void)setUp { [super setUp]; - + // The app delegate forwarder is already set via the load method, reset it for testing. [MSAppDelegateForwarder reset]; @@ -41,7 +41,7 @@ - (void)setUp { self.appMock = OCMClassMock([MSApplication class]); } -- (void)tearDown{ +- (void)tearDown { [MSAppDelegateForwarder reset]; [super tearDown]; } @@ -192,7 +192,9 @@ - (void)testSwizzleOriginalPushDelegate { }; // Adding a class method to a class requires its meta class. A meta class is the superclass of a class. - [self addSelector:instancesRespondToSelector implementation:instancesRespondToSelectorImp toClass:object_getClass([originalAppDelegate class])]; + [self addSelector:instancesRespondToSelector + implementation:instancesRespondToSelectorImp + toClass:object_getClass([originalAppDelegate class])]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -334,7 +336,9 @@ - (void)testSwizzleOriginalOpenURLDelegate { }; // Adding a class method to a class requires its meta class. - [self addSelector:instancesRespondToSelector implementation:instancesRespondToSelectorImp toClass:object_getClass([originalAppDelegate class])]; + [self addSelector:instancesRespondToSelector + implementation:instancesRespondToSelectorImp + toClass:object_getClass([originalAppDelegate class])]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:selectorToSwizzle]; /* @@ -393,22 +397,19 @@ - (void)testWithoutCustomDelegate { SEL originalOpenURLSel = @selector(application:openURL:options:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; - id originalOpenURLImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { + id originalOpenURLImp = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options) { - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLSel implementation:originalOpenURLImp toInstance:originalAppDelegate]; // When - BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - options:expectedOptions]; + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; // Then assertThatUnsignedLong(MSAppDelegateForwarder.delegates.count, equalToUnsignedLong(0)); @@ -428,18 +429,19 @@ - (void)testWithoutCustomDelegateNotReturningValue { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationsWithDeviceTokenSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidRegisterForRemoteNotificationsWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:originalDidRegisterForRemoteNotificationsWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationsWithDeviceTokenImp toInstance:originalAppDelegate]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationsWithDeviceTokenSel + implementation:originalDidRegisterForRemoteNotificationsWithDeviceTokenImp + toInstance:originalAppDelegate]; // When - [originalAppDelegate application:self.appMock - didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then assertThatUnsignedLong(MSAppDelegateForwarder.delegates.count, equalToUnsignedLong(0)); @@ -460,20 +462,20 @@ - (void)testWithOneCustomDelegate { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS90Sel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalOpenURLiOS90Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLiOS90Sel implementation:originalOpenURLiOS90Imp toInstance:originalAppDelegate]; SEL customOpenURLiOS90Sel = @selector(application:openURL:options:returnedValue:); id customAppDelegate = [self createCustomAppDelegateInstance]; id customOpenURLiOS90Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { // Then assertThat(application, is(appMock)); @@ -488,9 +490,7 @@ - (void)testWithOneCustomDelegate { [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - options:expectedOptions]; + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -509,24 +509,28 @@ - (void)testWithOneCustomDelegateNotReturningValue { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didRegisterNotificationSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidRegisterNotificationImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:didRegisterNotificationSel implementation:originalDidRegisterNotificationImp toInstance:originalAppDelegate]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:didRegisterNotificationSel + implementation:originalDidRegisterNotificationImp + toInstance:originalAppDelegate]; id customAppDelegate = [self createCustomAppDelegateInstance]; id customDidRegisterNotificationImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation fulfill]; - }; - [self addSelector:didRegisterNotificationSel implementation:customDidRegisterNotificationImp toInstance:customAppDelegate]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation fulfill]; + }; + [self addSelector:didRegisterNotificationSel + implementation:customDidRegisterNotificationImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; @@ -551,32 +555,39 @@ - (void)testDontForwardSelectorsNotToOverrideIfAlreadyImplementedByOriginalDeleg [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didReceiveRemoteNotificationSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidReceiveRemoteNotificationImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo, void (^completionHandler)(UIBackgroundFetchResult result)) { - - // Then - assertThat(application, is(appMock)); - assertThat(userInfo, is(expectedUserInfo)); - assertThat(completionHandler, is(expectedCompletionHandler)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:didReceiveRemoteNotificationSel implementation:originalDidReceiveRemoteNotificationImp toInstance:originalAppDelegate]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSDictionary *userInfo, + void (^completionHandler)(UIBackgroundFetchResult result)) { + + // Then + assertThat(application, is(appMock)); + assertThat(userInfo, is(expectedUserInfo)); + assertThat(completionHandler, is(expectedCompletionHandler)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:didReceiveRemoteNotificationSel + implementation:originalDidReceiveRemoteNotificationImp + toInstance:originalAppDelegate]; id customAppDelegate = [self createCustomAppDelegateInstance]; id customDidReceiveRemoteNotificationImp = - ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"This method is already implemented in the original delegate and is marked not to be swizzled."); - }; - [self addSelector:didReceiveRemoteNotificationSel implementation:customDidReceiveRemoteNotificationImp toInstance:customAppDelegate]; + ^(__attribute__((unused)) id itSelf, __attribute__((unused)) MSApplication *application, + __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"This method is already implemented in the original delegate and is marked not to be swizzled."); + }; + [self addSelector:didReceiveRemoteNotificationSel + implementation:customDidReceiveRemoteNotificationImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; // When [originalAppDelegate application:appMock - didReceiveRemoteNotification:expectedUserInfo - fetchCompletionHandler:expectedCompletionHandler]; + didReceiveRemoteNotification:expectedUserInfo + fetchCompletionHandler:expectedCompletionHandler]; // Then - assertThatBool([MSAppDelegateForwarder.selectorsNotToOverride containsObject:NSStringFromSelector(didReceiveRemoteNotificationSel)], + assertThatBool([MSAppDelegateForwarder.selectorsNotToOverride + containsObject:NSStringFromSelector(didReceiveRemoteNotificationSel)], isTrue()); [self waitForExpectations:@[ originalCalledExpectation ] timeout:1]; } @@ -597,51 +608,49 @@ - (void)testWithMultipleCustomOpenURLDelegates { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS90Sel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalOpenURLiOS90Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLiOS90Sel implementation:originalOpenURLiOS90Imp toInstance:originalAppDelegate]; SEL customOpenURLiOS90Sel = @selector(application:openURL:options:returnedValue:); id customAppDelegate1 = [self createCustomAppDelegateInstance]; id customOpenURLiOS90Imp1 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - [customCalledExpectation1 fulfill]; - return expectedReturnedValue; - }; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + [customCalledExpectation1 fulfill]; + return expectedReturnedValue; + }; [self addSelector:customOpenURLiOS90Sel implementation:customOpenURLiOS90Imp1 toInstance:customAppDelegate1]; id customAppDelegate2 = [self createCustomAppDelegateInstance]; id customOpenURLiOS90Imp2 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(options, is(expectedOptions)); - assertThatBool(returnedValue, is(@(expectedReturnedValue))); - [customCalledExpectation2 fulfill]; - return expectedReturnedValue; - }; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, id options, BOOL returnedValue) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(options, is(expectedOptions)); + assertThatBool(returnedValue, is(@(expectedReturnedValue))); + [customCalledExpectation2 fulfill]; + return expectedReturnedValue; + }; [self addSelector:customOpenURLiOS90Sel implementation:customOpenURLiOS90Imp2 toInstance:customAppDelegate2]; [MSAppDelegateForwarder addDelegate:customAppDelegate1]; [MSAppDelegateForwarder addDelegate:customAppDelegate2]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - options:expectedOptions]; + BOOL returnedValue = [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -663,42 +672,48 @@ - (void)testWithMultipleCustomPushDelegates { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; - SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp + toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = + @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); id customAppDelegate1 = [self createCustomAppDelegateInstance]; id customDidRegisterForRemoteNotificationWithDeviceTokenImp1 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation1 fulfill]; - }; - [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp1 toInstance:customAppDelegate1]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation1 fulfill]; + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp1 + toInstance:customAppDelegate1]; id customAppDelegate2 = [self createCustomAppDelegateInstance]; id customDidRegisterForRemoteNotificationWithDeviceTokenImp2 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [customCalledExpectation2 fulfill]; - }; - [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp2 toInstance:customAppDelegate2]; + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [customCalledExpectation2 fulfill]; + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp2 + toInstance:customAppDelegate2]; [MSAppDelegateForwarder addDelegate:customAppDelegate1]; [MSAppDelegateForwarder addDelegate:customAppDelegate2]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; // When - [originalAppDelegate application:self.appMock - didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then [self waitForExpectations:@[ originalCalledExpectation, customCalledExpectation1, customCalledExpectation2 ] @@ -717,38 +732,37 @@ - (void)testWithRemovedCustomOpenURLDelegate { SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; - id originalOpenURLiOS42Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; + id originalOpenURLiOS42Imp = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, + NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); id customAppDelegate = [self createCustomAppDelegateInstance]; - id customOpenURLiOS42Imp = - ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, - __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, - __attribute__((unused)) BOOL returnedValue) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - return expectedReturnedValue; - }; + id customOpenURLiOS42Imp = ^(__attribute__((unused)) id itSelf, __attribute__((unused)) MSApplication *application, + __attribute__((unused)) NSURL *url, __attribute__((unused)) NSString *sApplication, + __attribute__((unused)) id annotation, __attribute__((unused)) BOOL returnedValue) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + return expectedReturnedValue; + }; [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; [MSAppDelegateForwarder removeDelegate:customAppDelegate]; // When BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnnotation]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -767,29 +781,34 @@ - (void)testWithRemovedCustomDidRegisterForRemoteNotificationWithDeviceTokenDele [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; - SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp + toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = + @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); id customAppDelegate = [self createCustomAppDelegateInstance]; id customDidRegisterForRemoteNotificationWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - }; - [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:customAppDelegate]; + ^(__attribute__((unused)) id itSelf, __attribute__((unused)) MSApplication *application, + __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; [MSAppDelegateForwarder removeDelegate:customAppDelegate]; // When - [originalAppDelegate application:self.appMock - didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then [self waitForExpectations:@[ originalCalledExpectation ] timeout:1]; @@ -807,38 +826,37 @@ - (void)testDontForwardOpenURLOnDisable { SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; - id originalOpenURLiOS42Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - return expectedReturnedValue; - }; + id originalOpenURLiOS42Imp = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, + NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); id customAppDelegate = [self createCustomAppDelegateInstance]; - id customOpenURLiOS42Imp = - ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSURL *url, - __attribute__((unused)) NSString *sApplication, __attribute__((unused)) id annotation, - __attribute__((unused)) BOOL returnedValue) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - return expectedReturnedValue; - }; + id customOpenURLiOS42Imp = ^(__attribute__((unused)) id itSelf, __attribute__((unused)) MSApplication *application, + __attribute__((unused)) NSURL *url, __attribute__((unused)) NSString *sApplication, + __attribute__((unused)) id annotation, __attribute__((unused)) BOOL returnedValue) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + return expectedReturnedValue; + }; [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; MSAppDelegateForwarder.enabled = NO; // When BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnnotation]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -858,29 +876,34 @@ - (void)testDontForwardDidRegisterForRemoteNotificationWithDeviceTokenOnDisable [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalDidRegisterForRemoteNotificationWithDeviceTokenSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id originalDidRegisterForRemoteNotificationWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSData *deviceToken) { - - // Then - assertThat(application, is(appMock)); - assertThat(deviceToken, is(expectedToken)); - [originalCalledExpectation fulfill]; - }; - [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:originalAppDelegate]; - SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSData *deviceToken) { + + // Then + assertThat(application, is(appMock)); + assertThat(deviceToken, is(expectedToken)); + [originalCalledExpectation fulfill]; + }; + [self addSelector:originalDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:originalDidRegisterForRemoteNotificationWithDeviceTokenImp + toInstance:originalAppDelegate]; + SEL customDidRegisterForRemoteNotificationWithDeviceTokenSel = + @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:); id customAppDelegate = [self createCustomAppDelegateInstance]; id customDidRegisterForRemoteNotificationWithDeviceTokenImp = - ^(__attribute__((unused))id itSelf, __attribute__((unused)) MSApplication *application, __attribute__((unused)) NSData *deviceToken) { - - // Then - XCTFail(@"Custom delegate got called but is removed."); - }; - [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp toInstance:customAppDelegate]; + ^(__attribute__((unused)) id itSelf, __attribute__((unused)) MSApplication *application, + __attribute__((unused)) NSData *deviceToken) { + + // Then + XCTFail(@"Custom delegate got called but is removed."); + }; + [self addSelector:customDidRegisterForRemoteNotificationWithDeviceTokenSel + implementation:customDidRegisterForRemoteNotificationWithDeviceTokenImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; MSAppDelegateForwarder.enabled = NO; // When - [originalAppDelegate application:self.appMock - didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; + [originalAppDelegate application:self.appMock didRegisterForRemoteNotificationsWithDeviceToken:expectedToken]; // Then [self waitForExpectations:@[ originalCalledExpectation ] timeout:1]; @@ -902,24 +925,24 @@ - (void)testReturnValueChaining { SEL originalOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:originalOpenURLiOS42Sel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; - id originalOpenURLiOS42Imp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation) { - - // Then - assertThat(application, is(appMock)); - assertThat(url, is(expectedURL)); - assertThat(sApplication, nilValue()); - assertThat(annotation, is(expectedAnnotation)); - [originalCalledExpectation fulfill]; - expectedReturnedValue = initialReturnValue; - return expectedReturnedValue; - }; + id originalOpenURLiOS42Imp = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, + NSString *sApplication, id annotation) { + + // Then + assertThat(application, is(appMock)); + assertThat(url, is(expectedURL)); + assertThat(sApplication, nilValue()); + assertThat(annotation, is(expectedAnnotation)); + [originalCalledExpectation fulfill]; + expectedReturnedValue = initialReturnValue; + return expectedReturnedValue; + }; [self addSelector:originalOpenURLiOS42Sel implementation:originalOpenURLiOS42Imp toInstance:originalAppDelegate]; SEL customOpenURLiOS42Sel = @selector(application:openURL:sourceApplication:annotation:returnedValue:); id customAppDelegate1 = [self createCustomAppDelegateInstance]; - id customOpenURLiOS42Imp1 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - + id customOpenURLiOS42Imp1 = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, + NSString *sApplication, id annotation, BOOL returnedValue) { + // Then assertThat(application, is(appMock)); assertThat(url, is(expectedURL)); @@ -932,9 +955,9 @@ - (void)testReturnValueChaining { }; [self addSelector:customOpenURLiOS42Sel implementation:customOpenURLiOS42Imp1 toInstance:customAppDelegate1]; id customAppDelegate2 = [self createCustomAppDelegateInstance]; - id customOpenURLiOS42Imp2 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSURL *url, NSString *sApplication, id annotation, BOOL returnedValue) { - + id customOpenURLiOS42Imp2 = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSURL *url, + NSString *sApplication, id annotation, BOOL returnedValue) { + // Then assertThat(application, is(appMock)); assertThat(url, is(expectedURL)); @@ -952,9 +975,9 @@ - (void)testReturnValueChaining { // When BOOL returnedValue = [originalAppDelegate application:self.appMock - openURL:expectedURL - sourceApplication:nil - annotation:expectedAnnotation]; + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnnotation]; // Then assertThatBool(returnedValue, is(@(expectedReturnedValue))); @@ -974,16 +997,17 @@ - (void)testOpenURLForwardMethodNotImplementedByOriginalDelegate { [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:didFailToRegisterForNotifSel]; id originalAppDelegate = [self createOriginalAppDelegateInstance]; id customAppDelegate = [self createCustomAppDelegateInstance]; - id didFailToRegisterForNotifImp = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSError *error) { - + id didFailToRegisterForNotifImp = ^(__attribute__((unused)) id itSelf, MSApplication *application, NSError *error) { + // Then assertThat(application, is(appMock)); assertThat(error, is(expectedError)); [customCalledExpectation fulfill]; }; - [self addSelector:didFailToRegisterForNotifSel implementation:didFailToRegisterForNotifImp toInstance:customAppDelegate]; + [self addSelector:didFailToRegisterForNotifSel + implementation:didFailToRegisterForNotifImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; @@ -1008,25 +1032,25 @@ - (void)testDidReceiveNotification { XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; // Setup an empty original delegate. - Class originalAppDelegateClass = [self createInstanceConformingToProtocol:@protocol(MSApplicationDelegate)]; - id originalAppDelegate = [originalAppDelegateClass new]; + id originalAppDelegate = + [self createInstanceConformingToProtocol:@protocol(MSApplicationDelegate)]; SEL applicationDidFinishLaunchingSel = @selector(applicationDidFinishLaunching:); [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:applicationDidFinishLaunchingSel]; // Setup a custom delegate. id customAppDelegate = [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; - id applicationDidFinishLaunchingImp = - ^(NSNotification *notification) { + id applicationDidFinishLaunchingImp = ^(__attribute__((unused)) id itSelf, NSNotification *notification) { - // Then - XCTAssertNotNil(notification); - NSUserNotification *userNotification = - [notification.userInfo objectForKey:NSApplicationLaunchUserNotificationKey]; - XCTAssertNotNil(userNotification); - assertThat(userNotification.userInfo, is(expectedUserInfo)); - [customCalledExpectation fulfill]; - }; - [self addSelector:applicationDidFinishLaunchingSel implementation:applicationDidFinishLaunchingImp toInstance:customAppDelegate]; + // Then + XCTAssertNotNil(notification); + NSUserNotification *userNotification = [notification.userInfo objectForKey:NSApplicationLaunchUserNotificationKey]; + XCTAssertNotNil(userNotification); + assertThat(userNotification.userInfo, is(expectedUserInfo)); + [customCalledExpectation fulfill]; + }; + [self addSelector:applicationDidFinishLaunchingSel + implementation:applicationDidFinishLaunchingImp + toInstance:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; @@ -1064,28 +1088,32 @@ - (void)testDidReceiveRemoteNotification { // Setup a custom delegate. id customAppDelegate = [self createCustomAppDelegateInstance]; id didReceiveRemoteNotificationImp1 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo) { - - // Then - assertThat(application, is(appMock)); - assertThat(userInfo, is(expectedUserInfo)); - }; - [self addSelector:didReceiveRemoteNotificationSel1 implementation:didReceiveRemoteNotificationImp1 toInstance:customAppDelegate]; - id didReceiveRemoteNotificationImp2 = - ^(__attribute__((unused))id itSelf, MSApplication *application, NSDictionary *userInfo, void (^fetchHandler)(UIBackgroundFetchResult)) { - + ^(__attribute__((unused)) id itSelf, MSApplication *application, NSDictionary *userInfo) { + + // Then + assertThat(application, is(appMock)); + assertThat(userInfo, is(expectedUserInfo)); + }; + [self addSelector:didReceiveRemoteNotificationSel1 + implementation:didReceiveRemoteNotificationImp1 + toInstance:customAppDelegate]; + id didReceiveRemoteNotificationImp2 = ^(__attribute__((unused)) id itSelf, MSApplication *application, + NSDictionary *userInfo, void (^fetchHandler)(UIBackgroundFetchResult)) { + // Then assertThat(application, is(appMock)); assertThat(userInfo, is(expectedUserInfo)); assertThat(fetchHandler, is(fetchHandler)); - + // The original handler must only be called after all delegate did run. assertThatBool(isOriginalHandlerCalled, isFalse()); fetchHandler(expectedFetchResult); assertThatBool(isOriginalHandlerCalled, isFalse()); [customCalledExpectation fulfill]; }; - [self addSelector:didReceiveRemoteNotificationSel2 implementation:didReceiveRemoteNotificationImp2 toInstance:customAppDelegate]; + [self addSelector:didReceiveRemoteNotificationSel2 + implementation:didReceiveRemoteNotificationImp2 + toInstance:customAppDelegate]; [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [MSAppDelegateForwarder addDelegate:customAppDelegate]; @@ -1103,36 +1131,32 @@ - (void)testDidReceiveRemoteNotification { assertThatInteger(forwardedFetchResult, equalToInteger(expectedFetchResult)); } -#endif - -#if !TARGET_OS_OSX - - (void)testDontSwizzleDeprecatedAPIIfNoAPIImplemented { - + /* * If */ - + // Mock a custom app delegate. id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); [MSAppDelegateForwarder addDelegate:customDelegate]; NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; id expectedOptions = @{}; OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:NO]); - + // App delegate not implementing any API. SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); SEL newSelector = @selector(application:openURL:options:); id originalAppDelegate = [self createOriginalAppDelegateInstance]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; - + /* * When */ [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; - + /* * Then */ @@ -1142,17 +1166,21 @@ - (void)testDontSwizzleDeprecatedAPIIfNoAPIImplemented { } - (void)testSwizzleDeprecatedAPIIfNoNewAPIImplemented { - + /* * If */ - + // Mock a custom app delegate. id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); [MSAppDelegateForwarder addDelegate:customDelegate]; NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; id expectedAnotation = @{}; - OCMExpect([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); + OCMExpect([customDelegate application:self.appMock + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnotation + returnedValue:YES]); // App delegate implementing just the deprecated API. SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); @@ -1160,60 +1188,64 @@ - (void)testSwizzleDeprecatedAPIIfNoNewAPIImplemented { id originalAppDelegate = [self createOriginalAppDelegateInstance]; __block short nbCalls = 0; id selectorImp = ^{ - nbCalls ++; + nbCalls++; return YES; }; [self addSelector:deprecatedSelector implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; - + /* * When */ [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation]; - + /* * Then */ assertThatBool([originalAppDelegate respondsToSelector:newSelector], isFalse()); assertThatBool([originalAppDelegate respondsToSelector:deprecatedSelector], isTrue()); assertThatShort(nbCalls, equalToShort(1)); - OCMVerify([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); + OCMVerify([customDelegate application:self.appMock + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnotation + returnedValue:YES]); } - (void)testSwizzleDeprecatedAPIIfJustNewAPIImplemented { - + /* * If */ - + // Mock a custom app delegate. id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); [MSAppDelegateForwarder addDelegate:customDelegate]; NSURL *expectedURL = [NSURL URLWithString:@"https://www.contoso.com/sending-positive-waves"]; id expectedOptions = @{}; OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); - + // App delegate implementing just the new API. SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); SEL newSelector = @selector(application:openURL:options:); id originalAppDelegate = [self createOriginalAppDelegateInstance]; __block short nbCalls = 0; id selectorImp = ^{ - nbCalls ++; + nbCalls++; return YES; }; [self addSelector:newSelector implementation:selectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; - + /* * When */ [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; - + /* * Then */ @@ -1224,11 +1256,11 @@ - (void)testSwizzleDeprecatedAPIIfJustNewAPIImplemented { } - (void)testSwizzleDeprecatedAPIIfAllAPIsImplemented { - + /* * If */ - + // Mock a custom app delegate. id customDelegate = OCMProtocolMock(@protocol(MSAppDelegate)); [MSAppDelegateForwarder addDelegate:customDelegate]; @@ -1236,8 +1268,12 @@ - (void)testSwizzleDeprecatedAPIIfAllAPIsImplemented { id expectedAnotation = @{}; id expectedOptions = @{}; OCMExpect([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); - OCMExpect([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); - + OCMExpect([customDelegate application:self.appMock + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnotation + returnedValue:YES]); + // App delegate implementing all the APIs. SEL deprecatedSelector = @selector(application:openURL:sourceApplication:annotation:); SEL newSelector = @selector(application:openURL:options:); @@ -1245,25 +1281,25 @@ - (void)testSwizzleDeprecatedAPIIfAllAPIsImplemented { __block short deprecatedSelectorNbCalls = 0; __block short newSelectorNbCalls = 0; id deprecatedSelectorImp = ^{ - deprecatedSelectorNbCalls ++; + deprecatedSelectorNbCalls++; return YES; }; id newSelectorImp = ^{ - newSelectorNbCalls ++; + newSelectorNbCalls++; return YES; }; [self addSelector:deprecatedSelector implementation:deprecatedSelectorImp toInstance:originalAppDelegate]; [self addSelector:newSelector implementation:newSelectorImp toInstance:originalAppDelegate]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:deprecatedSelector]; [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:newSelector]; - + /* * When */ [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; [originalAppDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation]; [originalAppDelegate application:self.appMock openURL:expectedURL options:expectedOptions]; - + /* * Then */ @@ -1272,7 +1308,11 @@ - (void)testSwizzleDeprecatedAPIIfAllAPIsImplemented { assertThatShort(newSelectorNbCalls, equalToShort(1)); assertThatShort(deprecatedSelectorNbCalls, equalToShort(1)); OCMVerify([customDelegate application:self.appMock openURL:expectedURL options:expectedOptions returnedValue:YES]); - OCMVerify([customDelegate application:self.appMock openURL:expectedURL sourceApplication:nil annotation:expectedAnotation returnedValue:YES]); + OCMVerify([customDelegate application:self.appMock + openURL:expectedURL + sourceApplication:nil + annotation:expectedAnotation + returnedValue:YES]); } #endif @@ -1299,11 +1339,11 @@ - (id)createInstanceWithBaseClass:(Class) class andConformItToProtocol:(Protocol return [newClass new]; } -- (id)createOriginalAppDelegateInstance{ + - (id)createOriginalAppDelegateInstance { return [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; } -- (id)createCustomAppDelegateInstance{ +- (id)createCustomAppDelegateInstance { return [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; } @@ -1311,7 +1351,7 @@ - (void)addSelector:(SEL)selector implementation:(id)block toInstance:(id)instan [self addSelector:selector implementation:block toClass:[instance class]]; } -- (void)addSelector:(SEL)selector implementation:(id)block toClass:(id)class { +- (void)addSelector:(SEL)selector implementation:(id)block toClass:(id) class { Method method = class_getInstanceMethod(class, selector); const char *types = method_getTypeEncoding(method); IMP imp = imp_implementationWithBlock(block); From 66856b8d7edb885b904e09d170be3601c5b2f2ad Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 5 Sep 2017 12:18:54 -0700 Subject: [PATCH 15/55] Add a workaround to fill 999 for millisecond --- .../Internals/Util/MSErrorLogFormatter.m | 6 ++++++ .../MSErrorLogFormatterTests.mm | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/Util/MSErrorLogFormatter.m b/MobileCenterCrashes/MobileCenterCrashes/Internals/Util/MSErrorLogFormatter.m index 7b29881a15..efd36f8645 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/Util/MSErrorLogFormatter.m +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/Util/MSErrorLogFormatter.m @@ -223,6 +223,12 @@ + (MSAppleErrorLog *)errorLogFromCrashReport:(MSPLCrashReport *)report { errorLog.appLaunchTimestamp = [self getAppLaunchTimeFromReport:report]; errorLog.timestamp = [self getCrashTimeFromReport:report]; + // FIXME: PLCrashReporter doesn't support millisecond precision, here is a workaround to fill 999 for its millisecond. + double timestampInSeconds = [errorLog.timestamp timeIntervalSince1970]; + if (timestampInSeconds - (int)timestampInSeconds == 0) { + errorLog.timestamp = [NSDate dateWithTimeIntervalSince1970:(timestampInSeconds + 0.999)]; + } + // CPU Type and Subtype for the crash. We need to query the binary images for that. NSArray *images = report.images; for (MSPLCrashReportBinaryImageInfo *image in images) { diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSErrorLogFormatterTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSErrorLogFormatterTests.mm index ee006ad305..20cb15bf2a 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSErrorLogFormatterTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSErrorLogFormatterTests.mm @@ -43,7 +43,10 @@ - (void)testCreateErrorReport { XCTAssertEqual(errorReport.signal, crashReport.signalInfo.name); XCTAssertEqual(errorReport.exceptionName, nil); XCTAssertEqual(errorReport.exceptionReason, nil); - assertThat(errorReport.appErrorTime, equalTo(crashReport.systemInfo.timestamp)); + + // FIXME: PLCrashReporter doesn't support millisecond precision, here is a workaround to fill 999 for its millisecond. + XCTAssertEqual([errorReport.appErrorTime timeIntervalSince1970], + [crashReport.systemInfo.timestamp timeIntervalSince1970] + 0.999); assertThat(errorReport.appStartTime, equalTo(crashReport.processInfo.processStartTime)); /* @@ -68,7 +71,10 @@ - (void)testCreateErrorReport { XCTAssertEqual(errorReport.signal, crashReport.signalInfo.name); assertThat(errorReport.exceptionName, equalTo(crashReport.exceptionInfo.exceptionName)); assertThat(errorReport.exceptionReason, equalTo(crashReport.exceptionInfo.exceptionReason)); - assertThat(errorReport.appErrorTime, equalTo(crashReport.systemInfo.timestamp)); + + // FIXME: PLCrashReporter doesn't support millisecond precision, here is a workaround to fill 999 for its millisecond. + XCTAssertEqual([errorReport.appErrorTime timeIntervalSince1970], + [crashReport.systemInfo.timestamp timeIntervalSince1970] + 0.999); assertThat(errorReport.appStartTime, equalTo(crashReport.processInfo.processStartTime)); /* @@ -424,7 +430,10 @@ - (void)assertIsCrashProbeReportValidConverted:(NSString *)filename { assertThat(errorLog.parentProcessId, equalTo(@(crashReport.processInfo.parentProcessID))); assertThat(errorLog.parentProcessName, equalTo(crashReport.processInfo.parentProcessName)); assertThat(errorLog.errorThreadId, equalTo(@(crashedThread.threadNumber))); - assertThat(errorLog.timestamp, equalTo(crashReport.systemInfo.timestamp)); + + // FIXME: PLCrashReporter doesn't support millisecond precision, here is a workaround to fill 999 for its millisecond. + XCTAssertEqual([errorLog.timestamp timeIntervalSince1970], + [crashReport.systemInfo.timestamp timeIntervalSince1970] + 0.999); assertThat(errorLog.appLaunchTimestamp, equalTo(crashReport.processInfo.processStartTime)); NSArray *images = crashReport.images; From d00780a176f44825f1438740bd6fbb989f735e67 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Wed, 6 Sep 2017 10:39:38 -0700 Subject: [PATCH 16/55] Aesthetical fix on MSAppDelegateForwarder.m --- .../Internals/AppDelegate/MSAppDelegateForwarder.m | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 49445a5c9d..70e67c4944 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -94,10 +94,10 @@ + (void)setDelegates:(NSHashTable> *)delegates { + (NSDictionary *)deprecatedSelectors { if (!_deprecatedSelectors) { -#if !TARGET_OS_OSX - _deprecatedSelectors = @{kMSOpenURLOptions : kMSOpenURLSourceApplicationAnnotation}; -#else +#if TARGET_OS_OSX _deprecatedSelectors = @{}; +#else + _deprecatedSelectors = @{kMSOpenURLOptions : kMSOpenURLSourceApplicationAnnotation}; #endif } return _deprecatedSelectors; @@ -211,8 +211,10 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector if (deprecatedSelectorStr && [originalClass instancesRespondToSelector:NSSelectorFromString(deprecatedSelectorStr)]) { - // An implementation for the deprecated selector exists. Don't add the new method, it might eclipse the original - // implementation. + /* + * An implementation for the deprecated selector exists. Don't add the new method, it might eclipse the original + * implementation. + */ warningMsg = [NSString stringWithFormat: @"No implementation found for this selector, though an implementation of its deprecated API '%@' exists.", From 2e1557f69fe79280d57dc2ed9f1bb66db8621e53 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 6 Sep 2017 11:36:08 -0700 Subject: [PATCH 17/55] Add more verbose logs --- .../Internals/Channel/MSChannelDefault.m | 16 ++++++++++++---- .../MobileCenter/Internals/Model/MSAbstractLog.m | 14 ++++++++++++++ .../Internals/Model/MSAbstractLogInternal.h | 9 +++++++++ .../MobileCenterCrashes/MSCrashes.mm | 8 +++++--- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/Channel/MSChannelDefault.m b/MobileCenter/MobileCenter/Internals/Channel/MSChannelDefault.m index d74d255695..74f4d9c107 100644 --- a/MobileCenter/MobileCenter/Internals/Channel/MSChannelDefault.m +++ b/MobileCenter/MobileCenter/Internals/Channel/MSChannelDefault.m @@ -1,4 +1,4 @@ -#import "MSChannelDefault.h" +#import "MSAbstractLogInternal.h" #import "MSChannelDefaultPrivate.h" #import "MSMobileCenterErrors.h" #import "MSMobileCenterInternal.h" @@ -140,9 +140,17 @@ - (void)flushQueue { self.pendingBatchQueueFull = YES; } MSLogContainer *container = [[MSLogContainer alloc] initWithBatchId:batchId andLogs:logArray]; - MSLogDebug([MSMobileCenter logTag], @"Sending %lu log(s), group Id: %@, batch Id:%@, payload:\n%@", - (unsigned long)[container.logs count], self.configuration.groupId, batchId, - [container serializeLogWithPrettyPrinting:YES]); + + // Optimization. If the current log level is greater than MSLogLevelDebug, we can skip it. + if ([MSMobileCenter logLevel] <= MSLogLevelDebug) { + unsigned long count = [container.logs count]; + for (unsigned long i = 0; i < count; i++) { + MSLogDebug([MSMobileCenter logTag], + @"Sending %lu/%lu log(s), group Id: %@, batch Id:%@, payload:\n%@", (i + 1), count, + self.configuration.groupId, batchId, + [(MSAbstractLog *)container.logs[i] serializeLogWithPrettyPrinting:YES]); + } + } // Notify delegates. [self enumerateDelegatesForSelector:@selector(channel:willSendLog:) diff --git a/MobileCenter/MobileCenter/Internals/Model/MSAbstractLog.m b/MobileCenter/MobileCenter/Internals/Model/MSAbstractLog.m index 161596eda5..88c55331e9 100644 --- a/MobileCenter/MobileCenter/Internals/Model/MSAbstractLog.m +++ b/MobileCenter/MobileCenter/Internals/Model/MSAbstractLog.m @@ -69,4 +69,18 @@ - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.device forKey:kMSDevice]; } +#pragma mark - Utility + +- (NSString *)serializeLogWithPrettyPrinting:(BOOL)prettyPrint { + NSString *jsonString; + NSJSONWritingOptions printOptions = prettyPrint ? NSJSONWritingPrettyPrinted : (NSJSONWritingOptions)0; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self serializeToDictionary] options:printOptions error:nil]; + + if (jsonData) { + jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; + } + return jsonString; +} + @end diff --git a/MobileCenter/MobileCenter/Internals/Model/MSAbstractLogInternal.h b/MobileCenter/MobileCenter/Internals/Model/MSAbstractLogInternal.h index 8d34b374cd..549cf5dc6f 100644 --- a/MobileCenter/MobileCenter/Internals/Model/MSAbstractLogInternal.h +++ b/MobileCenter/MobileCenter/Internals/Model/MSAbstractLogInternal.h @@ -4,4 +4,13 @@ @interface MSAbstractLog () +/** + * Serialize logs into a JSON string. + * + * @param prettyPrint boolean indicates pretty printing. + * + * @return A serialized string. + */ +- (NSString *)serializeLogWithPrettyPrinting:(BOOL)prettyPrint; + @end diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm index 7be6b47c62..f7ef864d39 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm @@ -424,6 +424,7 @@ - (void)onEnqueuingLog:(id)log withInternalId:(NSString *)internalId { NSNumberFormatter *timestampFormatter = [[NSNumberFormatter alloc] init]; timestampFormatter.numberStyle = NSNumberFormatterDecimalStyle; long indexToDelete = 0; + MSLogVerbose([MSCrashes logTag], @"Storing a log to Crashes Buffer: (sid: %@, type: %@)", log.sid, log.type); for (auto it = msCrashesLogBuffer.begin(), end = msCrashesLogBuffer.end(); it != end; ++it) { // We've found an empty element, buffer our log. @@ -482,15 +483,15 @@ - (void)onEnqueuingLog:(id)log withInternalId:(NSString *)internalId { - (void)onFinishedPersistingLog:(id)log withInternalId:(NSString *)internalId { (void)log; - [self deleteBufferedLogWithInternalId:internalId]; + [self deleteBufferedLog:log withInternalId:internalId]; } - (void)onFailedPersistingLog:(id)log withInternalId:(NSString *)internalId { (void)log; - [self deleteBufferedLogWithInternalId:internalId]; + [self deleteBufferedLog:log withInternalId:internalId]; } -- (void)deleteBufferedLogWithInternalId:(NSString *)internalId { +- (void)deleteBufferedLog:(id)log withInternalId:(NSString *)internalId { @synchronized(self) { for (auto it = msCrashesLogBuffer.begin(), end = msCrashesLogBuffer.end(); it != end; ++it) { NSString *bufferId = [NSString stringWithCString:it->internalId.c_str() encoding:NSUTF8StringEncoding]; @@ -506,6 +507,7 @@ - (void)deleteBufferedLogWithInternalId:(NSString *)internalId { * delete the buffer file. */ unlink(it->bufferPath.c_str()); + MSLogVerbose([MSCrashes logTag], @"Deleted a log from Crashes Buffer (sid: %@, type: %@)", log.sid, log.type); MSLogVerbose([MSCrashes logTag], @"Deleted crash buffer file: %@.", [NSString stringWithCString:it->bufferPath.c_str() encoding:[NSString defaultCStringEncoding]]); } From 116d9b1f545eee36db8925a4f2aa593eae0e6a54 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Wed, 6 Sep 2017 15:14:17 -0700 Subject: [PATCH 18/55] remove commented out things and empty lines --- .../MobileCenterDistribute/MSDistribute.m | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index d9a0c01d77..ff1a3fdb8d 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -40,9 +40,6 @@ @implementation MSDistribute @synthesize channelConfiguration = _channelConfiguration; - - - #pragma mark - Service initialization - (instancetype)init { @@ -230,9 +227,9 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { if(authClazz) { // Manipulate App UI on the main queue. -// dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ [self openURLInAuthenticationSessionWith:url fromClass:authClazz]; -// }); + }); } else { // iOS 9 and 10 From 6c1c61ba58bdc275dd85c34863aaffc86a199fa9 Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Thu, 7 Sep 2017 18:24:55 -0700 Subject: [PATCH 19/55] Add handled error log type --- .../project.pbxproj | 14 ++ .../Internals/Model/MSHandledErrorLog.h | 21 +++ .../Internals/Model/MSHandledErrorLog.m | 60 +++++++++ .../MSHandledErrorLogTests.m | 125 ++++++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h create mode 100644 MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m create mode 100644 MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m diff --git a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj index 30d274cafc..96fd254834 100644 --- a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj +++ b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj @@ -339,6 +339,10 @@ 6EC99A3C1D416CCF0016C325 /* live_report_xamarin.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 6EC99A351D416CCF0016C325 /* live_report_xamarin.plcrash */; }; 6EC99A3D1D416CCF0016C325 /* log_report_xamarin in Resources */ = {isa = PBXBuildFile; fileRef = 6EC99A361D416CCF0016C325 /* log_report_xamarin */; }; 8024743B1EAE077800AEC284 /* MSErrorAttachmentLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 8024743A1EAE077800AEC284 /* MSErrorAttachmentLog.m */; }; + 922446841F621F3A00E4034A /* MSHandledErrorLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446831F621F3A00E4034A /* MSHandledErrorLog.m */; }; + 9224468C1F62276C00E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; + 9224468D1F62277400E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; + 9224468E1F62277500E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; B24F3F0F1D93368F00827213 /* MSErrorLogFormatterTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = B24F3F0E1D93368F00827213 /* MSErrorLogFormatterTests.mm */; }; B24F3F121D9341BC00827213 /* MSErrorLogFormatterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = B24F3F101D93417B00827213 /* MSErrorLogFormatterPrivate.h */; }; B2A0A71C1D9C2AE700729A58 /* MSCrashesTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A0A71B1D9C2AE700729A58 /* MSCrashesTestUtil.m */; }; @@ -566,6 +570,9 @@ 6EC99A351D416CCF0016C325 /* live_report_xamarin.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file; path = live_report_xamarin.plcrash; sourceTree = ""; }; 6EC99A361D416CCF0016C325 /* log_report_xamarin */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = log_report_xamarin; sourceTree = ""; }; 8024743A1EAE077800AEC284 /* MSErrorAttachmentLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSErrorAttachmentLog.m; sourceTree = ""; }; + 922446821F621D4500E4034A /* MSHandledErrorLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSHandledErrorLog.h; sourceTree = ""; }; + 922446831F621F3A00E4034A /* MSHandledErrorLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSHandledErrorLog.m; sourceTree = ""; }; + 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSHandledErrorLogTests.m; sourceTree = ""; }; B24F3F0E1D93368F00827213 /* MSErrorLogFormatterTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MSErrorLogFormatterTests.mm; sourceTree = ""; }; B24F3F101D93417B00827213 /* MSErrorLogFormatterPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSErrorLogFormatterPrivate.h; sourceTree = ""; }; B2A0A71A1D9C2AE700729A58 /* MSCrashesTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSCrashesTestUtil.h; sourceTree = ""; }; @@ -908,6 +915,7 @@ 6E7D5C811D3EC06C009EC9AC /* MSConstants.h */, 350B29F31F1E6F1D009B91CF /* MSWrapperExceptionTests.m */, B2FF130B1DD12F61003DC677 /* MSAppleErrorLogTests.m */, + 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */, B2F120D41D6546740060DED7 /* MSErrorAttachmentLogTests.m */, 6E7D5C7F1D3EAEB5009EC9AC /* MSBinaryTests.m */, 59493B275715F01438B2E6FD /* MSCrashesUtilTests.m */, @@ -983,11 +991,13 @@ 6E7D5C651D3E9321009EC9AC /* MSBinary.h */, 6E7D5C661D3E9321009EC9AC /* MSBinary.m */, 6E7D5C691D3E9332009EC9AC /* MSAppleErrorLog.h */, + 922446821F621D4500E4034A /* MSHandledErrorLog.h */, 6E7D5C6A1D3E9332009EC9AC /* MSAppleErrorLog.m */, B2F120DF1D657CF10060DED7 /* MSErrorReport.m */, B2F120E61D657F4F0060DED7 /* MSErrorReportPrivate.h */, 6E7D5C711D3E9381009EC9AC /* MSThread.h */, 6E7D5C721D3E9381009EC9AC /* MSThread.m */, + 922446831F621F3A00E4034A /* MSHandledErrorLog.m */, ); path = Model; sourceTree = ""; @@ -1528,6 +1538,7 @@ 0446DF721F3B977100C8E338 /* MSErrorLogFormatterTests.mm in Sources */, 0446DF731F3B977100C8E338 /* MSCrashesTestUtil.m in Sources */, 0446DF741F3B977100C8E338 /* MSBinaryTests.m in Sources */, + 9224468E1F62277500E4034A /* MSHandledErrorLogTests.m in Sources */, 0446DF751F3B977100C8E338 /* MSWrapperExceptionManagerTests.m in Sources */, 0446DF761F3B977100C8E338 /* MSErrorAttachmentLogTests.m in Sources */, 0446DF771F3B977100C8E338 /* MSMockCrashesDelegate.m in Sources */, @@ -1575,6 +1586,7 @@ 0493276C1ECA170D00D0187A /* MSErrorLogFormatterTests.mm in Sources */, 0493276D1ECA170D00D0187A /* MSCrashesTestUtil.m in Sources */, 0493276E1ECA170D00D0187A /* MSBinaryTests.m in Sources */, + 9224468D1F62277400E4034A /* MSHandledErrorLogTests.m in Sources */, 049327701ECA170D00D0187A /* MSWrapperExceptionManagerTests.m in Sources */, 049327711ECA170D00D0187A /* MSErrorAttachmentLogTests.m in Sources */, 049327721ECA170D00D0187A /* MSMockCrashesDelegate.m in Sources */, @@ -1612,6 +1624,7 @@ files = ( B2F120E51D657CF10060DED7 /* MSErrorReport.m in Sources */, 6E73FE6B1D402F79008CDC15 /* MSCrashesCXXExceptionHandler.mm in Sources */, + 922446841F621F3A00E4034A /* MSHandledErrorLog.m in Sources */, B2CD3BFA1D80EE49000A8A91 /* MSAbstractErrorLog.m in Sources */, 3858A21A1E93F3B400535A69 /* MSErrorAttachmentLog+Utility.m in Sources */, 6E7D5C701D3E9346009EC9AC /* MSException.m in Sources */, @@ -1646,6 +1659,7 @@ B24F3F0F1D93368F00827213 /* MSErrorLogFormatterTests.mm in Sources */, B2A0A71C1D9C2AE700729A58 /* MSCrashesTestUtil.m in Sources */, 6E7D5C801D3EAEB5009EC9AC /* MSBinaryTests.m in Sources */, + 9224468C1F62276C00E4034A /* MSHandledErrorLogTests.m in Sources */, 35EF18E01DDBCF6C00731CA8 /* MSWrapperExceptionManagerTests.m in Sources */, B2F120D51D6546740060DED7 /* MSErrorAttachmentLogTests.m in Sources */, BA682CFA6F4C5A8841507CF7 /* MSMockCrashesDelegate.m in Sources */, diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h new file mode 100644 index 0000000000..9e6c116773 --- /dev/null +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h @@ -0,0 +1,21 @@ +#import +#import "MSAbstractErrorLog.h" + +@class MSException; + +/* + * Handled Error log for managed platforms (such as Xamarin, Unity, Android Dalvik/ART). + */ +@interface MSHandledErrorLog : MSAbstractLog + +/* + * Unique identifier for this error. + */ +@property(nonatomic, copy) NSString *errorId; + +/* + * The exception. + */ +@property(nonatomic) MSException *exception; + +@end diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m new file mode 100644 index 0000000000..7dca0859d2 --- /dev/null +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m @@ -0,0 +1,60 @@ +#import "MSHandledErrorLog.h" +#import "MSException.h" + +static NSString *const kMSTypeError = @"handled_error"; +static NSString *const kMSId = @"id"; +static NSString *const kMSException = @"exception"; + +@implementation MSHandledErrorLog + +- (instancetype)init { + if ((self = [super init])) { + self.type = kMSTypeError; + } + return self; +} + +- (NSMutableDictionary *)serializeToDictionary { + NSMutableDictionary *dict = [super serializeToDictionary]; + + if (self.errorId) { + dict[kMSId] = self.errorId; + } + if (self.exception) { + dict[kMSException] = [self.exception serializeToDictionary]; + } + return dict; +} + +- (BOOL)isValid { + return [super isValid] && self.errorId && self.exception; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[MSHandledErrorLog class]] || ![super isEqual:object]) { + return NO; + } + MSHandledErrorLog *errorLog = (MSHandledErrorLog *)object; + return ((!self.errorId && !errorLog.errorId) || + [self.errorId isEqual:errorLog.errorId]) && + ((!self.exception && !errorLog.exception) || [self.exception isEqual:errorLog.exception]); +} + +#pragma mark - NSCoding + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + _errorId = [coder decodeObjectForKey:kMSId]; + _exception = [coder decodeObjectForKey:kMSException]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + [coder encodeObject:self.errorId forKey:kMSId]; + [coder encodeObject:self.exception forKey:kMSException]; +} + +@end diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m b/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m new file mode 100644 index 0000000000..9f14c5f3e1 --- /dev/null +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m @@ -0,0 +1,125 @@ +#import "MSHandledErrorLog.h" +#import "MSCrashesTestUtil.h" +#import "MSException.h" +#import "MSTestFrameworks.h" + +@interface MSHandledErrorLogTests : XCTestCase + +@property(nonatomic) MSHandledErrorLog *sut; + +@end + +@implementation MSHandledErrorLogTests + +#pragma mark - Housekeeping + +- (void)setUp { + [super setUp]; + + self.sut = [self handledErrorLog]; +} + +- (void)tearDown { + [super tearDown]; +} + +#pragma mark - Helper + +- (MSHandledErrorLog *)handledErrorLog { + + MSHandledErrorLog *handledErrorLog = [MSHandledErrorLog new]; + handledErrorLog.type = @"handled_error"; + handledErrorLog.exception = [MSCrashesTestUtil exception]; + handledErrorLog.errorId = @"123"; + + return handledErrorLog; +} + +#pragma mark - Tests + +- (void)testInitializationWorks { + XCTAssertNotNil(self.sut); +} + +- (void)testSerializationToDictionaryWorks { + NSDictionary *actual = [self.sut serializeToDictionary]; + XCTAssertNotNil(actual); + assertThat(actual[@"type"], equalTo(self.sut.type)); + assertThat(actual[@"id"], equalTo(self.sut.errorId)); + + // Exception fields. + NSDictionary *exceptionDictionary = actual[@"exception"]; + XCTAssertNotNil(exceptionDictionary); + assertThat(exceptionDictionary[@"type"], equalTo(self.sut.exception.type)); + assertThat(exceptionDictionary[@"message"], equalTo(self.sut.exception.message)); + assertThat(exceptionDictionary[@"wrapper_sdk_name"], equalTo(self.sut.exception.wrapperSdkName)); +} + +- (void)testNSCodingSerializationAndDeserializationWorks { + + // When + NSData *serializedEvent = [NSKeyedArchiver archivedDataWithRootObject:self.sut]; + id actual = [NSKeyedUnarchiver unarchiveObjectWithData:serializedEvent]; + + // Then + assertThat(actual, notNilValue()); + assertThat(actual, instanceOf([MSHandledErrorLog class])); + + // The MSHandledErrorLog. + MSHandledErrorLog *actualLog = actual; + assertThat(actualLog, equalTo(self.sut)); + XCTAssertTrue([actualLog isEqual:self.sut]); + assertThat(actualLog.type, equalTo(self.sut.type)); + assertThat(actualLog.errorId, equalTo(self.sut.errorId)); + + // The exception field. + MSException *actualException = actualLog.exception; + assertThat(actualException.type, equalTo(self.sut.exception.type)); + assertThat(actualException.message, equalTo(self.sut.exception.message)); + assertThat(actualException.wrapperSdkName, equalTo(self.sut.exception.wrapperSdkName)); +} + +- (void)testIsEqual { + + // When + MSHandledErrorLog *first = [self handledErrorLog]; + MSHandledErrorLog *second = [self handledErrorLog]; + + // Then + XCTAssertTrue([first isEqual:second]); + + // When + second.errorId = MS_UUID_STRING; + + // Then + XCTAssertFalse([first isEqual:second]); +} + +- (void)testIsValid { + + // When + MSHandledErrorLog *log = [MSHandledErrorLog new]; + log.device = OCMClassMock([MSDevice class]); + OCMStub([log.device isValid]).andReturn(YES); + log.sid = @"sid"; + log.timestamp = [NSDate dateWithTimeIntervalSince1970:42]; + log.errorId = @"errorId"; + log.sid = MS_UUID_STRING; + + // Then + XCTAssertFalse([log isValid]); + + // When + log.errorId = MS_UUID_STRING; + + // Then + XCTAssertFalse([log isValid]); + + // When + log.exception = [MSCrashesTestUtil exception]; + + // Then + XCTAssertTrue([log isValid]); +} + +@end From 77ab7df9b9e84179ec335e5258de31b267e2b5bf Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 11:39:56 -0700 Subject: [PATCH 20/55] Remove swizzling of applicationDidFinishLaunching and use notification center instead --- .../AppDelegate/MSAppDelegateForwarder.m | 15 ------- .../Internals/AppDelegate/MSNSAppDelegate.h | 8 ---- .../Internal/MSPushAppDelegate.h | 4 -- .../Internal/MSPushAppDelegate.m | 18 +-------- .../MobileCenterPush/Internal/MSPushPrivate.h | 4 ++ MobileCenterPush/MobileCenterPush/MSPush.h | 9 ----- MobileCenterPush/MobileCenterPush/MSPush.m | 40 +++++++++---------- 7 files changed, 25 insertions(+), 73 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 70e67c4944..00b9c86c03 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -405,21 +405,6 @@ - (void)custom_application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:error]; } -#if TARGET_OS_OSX -- (void)custom_applicationDidFinishLaunching:(NSNotification *)notification { - IMP originalImp = NULL; - - // Forward to the original delegate. - [MSAppDelegateForwarder.originalImplementations[NSStringFromSelector(_cmd)] getValue:&originalImp]; - if (originalImp) { - ((void (*)(id, SEL, NSNotification *))originalImp)(self, _cmd, notification); - } - - // Forward to custom delegates. - [[MSAppDelegateForwarder sharedInstance] applicationDidFinishLaunching:(NSNotification *)notification]; -} -#endif - #if TARGET_OS_OSX - (void)custom_application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { #else diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSNSAppDelegate.h b/MobileCenter/MobileCenter/Internals/AppDelegate/MSNSAppDelegate.h index 77a5518edc..0eeb85cc3b 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSNSAppDelegate.h +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSNSAppDelegate.h @@ -52,14 +52,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo; -/** - * Sent by the default notification center after the application has been launched and initialized but before it has - * received its first event. - * - * @param notification A notification that caused the application launch. - */ -- (void)applicationDidFinishLaunching:(NSNotification *)notification; - @end NS_ASSUME_NONNULL_END diff --git a/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.h b/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.h index c75b174f98..8420f73b25 100644 --- a/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.h +++ b/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.h @@ -5,10 +5,6 @@ #import "MSUIAppDelegate.h" #endif -#if TARGET_OS_OSX -@interface MSPushAppDelegate : NSObject -#else @interface MSPushAppDelegate : NSObject -#endif @end diff --git a/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.m b/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.m index cf413f30d2..4828941379 100644 --- a/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.m +++ b/MobileCenterPush/MobileCenterPush/Internal/MSPushAppDelegate.m @@ -48,20 +48,6 @@ - (void)application:(__attribute__((unused))UIApplication *)application } #endif -#if TARGET_OS_OSX -- (void)applicationDidFinishLaunching:(NSNotification *)notification { - NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; - center.delegate = self; - [MSPush didReceiveNotification:notification]; -} - -- (void)userNotificationCenter:(NSUserNotificationCenter *)__unused center - didActivateNotification:(NSUserNotification *)notification { - [MSPush didReceiveUserNotification:notification]; -} - -#endif - @end #pragma mark - Swizzling @@ -74,9 +60,7 @@ + (void)load { [self addAppDelegateSelectorToSwizzle:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)]; [self addAppDelegateSelectorToSwizzle:@selector(application:didFailToRegisterForRemoteNotificationsWithError:)]; [self addAppDelegateSelectorToSwizzle:@selector(application:didReceiveRemoteNotification:)]; -#if TARGET_OS_OSX - [self addAppDelegateSelectorToSwizzle:@selector(applicationDidFinishLaunching:)]; -#else +#if !TARGET_OS_OSX [self addAppDelegateSelectorToSwizzle:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]; #endif } diff --git a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h index d36c09f637..6962579689 100644 --- a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h +++ b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h @@ -4,7 +4,11 @@ @protocol MSAppDelegate; +#if TARGET_OS_OSX +@interface MSPush () +#else @interface MSPush () +#endif @property(nonatomic) id delegate; diff --git a/MobileCenterPush/MobileCenterPush/MSPush.h b/MobileCenterPush/MobileCenterPush/MSPush.h index 956e13946e..bba784fe48 100644 --- a/MobileCenterPush/MobileCenterPush/MSPush.h +++ b/MobileCenterPush/MobileCenterPush/MSPush.h @@ -23,15 +23,6 @@ NS_ASSUME_NONNULL_BEGIN + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; #if TARGET_OS_OSX -/** - * Callback for notification with notification on macOS. - * - * @param notification The notification that triggered the application launch. - * - * @return YES if the notification was sent via Mobile Center. - */ -+ (BOOL)didReceiveNotification:(NSNotification *)notification; - /** * Callback for notification with user notification on macOS. * diff --git a/MobileCenterPush/MobileCenterPush/MSPush.m b/MobileCenterPush/MobileCenterPush/MSPush.m index 13394f469b..791afae7bf 100644 --- a/MobileCenterPush/MobileCenterPush/MSPush.m +++ b/MobileCenterPush/MobileCenterPush/MSPush.m @@ -98,10 +98,6 @@ + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { } #if TARGET_OS_OSX -+ (BOOL)didReceiveNotification:(NSNotification *)notification { - return [[self sharedInstance] didReceiveNotification:notification]; -} - + (BOOL)didReceiveUserNotification:(NSUserNotification *)notification { return [[self sharedInstance] didReceiveUserNotification:notification]; } @@ -120,12 +116,23 @@ + (void)setDelegate:(nullable id)delegate { - (void)applyEnabledState:(BOOL)isEnabled { [super applyEnabledState:isEnabled]; if (isEnabled) { +#if TARGET_OS_OSX + [NSUserNotificationCenter defaultUserNotificationCenter].delegate = self; + [MS_NOTIFICATION_CENTER addObserver:self + selector:@selector(applicationDidFinishLaunching:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; +#endif [MSAppDelegateForwarder addDelegate:self.appDelegate]; if (!self.pushTokenHasBeenSent) { [self registerForRemoteNotifications]; } MSLogInfo([MSPush logTag], @"Push service has been enabled."); } else { +#if TARGET_OS_OSX + [NSUserNotificationCenter defaultUserNotificationCenter].delegate = nil; + [MS_NOTIFICATION_CENTER removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil]; +#endif [MSAppDelegateForwarder removeDelegate:self.appDelegate]; MSLogInfo([MSPush logTag], @"Push service has been disabled."); } @@ -170,18 +177,6 @@ - (void)registerForRemoteNotifications { #endif } -#if TARGET_OS_OSX - -// TODO: Implement macOS. Seems it is dead code. -#else -- (void)application:(UIApplication *)application - didRegisterUserNotificationSettings:(UIUserNotificationSettings *)__unused notificationSettings { - - // register to receive notifications - [application registerForRemoteNotifications]; -} -#endif - - (NSString *)convertTokenToString:(NSData *)token { if (!token) return nil; @@ -215,10 +210,6 @@ - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { } #if TARGET_OS_OSX -- (BOOL)didReceiveNotification:(NSNotification *)notification { - return [self didReceiveUserNotification:[notification.userInfo objectForKey:NSApplicationLaunchUserNotificationKey]]; -} - - (BOOL)didReceiveUserNotification:(NSUserNotification *)notification { if (notification && [self didReceiveRemoteNotification:notification.userInfo fromUserNotification:YES]) { NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; @@ -229,6 +220,15 @@ - (BOOL)didReceiveUserNotification:(NSUserNotification *)notification { } return NO; } + +- (void)applicationDidFinishLaunching:(NSNotification *)notification { + [self didReceiveUserNotification:[notification.userInfo objectForKey:NSApplicationLaunchUserNotificationKey]]; +} + +- (void)userNotificationCenter:(NSUserNotificationCenter *)__unused center + didActivateNotification:(NSUserNotification *)notification { + [MSPush didReceiveUserNotification:notification]; +} #endif - (BOOL)didReceiveRemoteNotification:(NSDictionary *)userInfo fromUserNotification:(BOOL)userNotification { From f176509905c2dfd7e771a05b57c05f1f8b537f79 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 12:34:53 -0700 Subject: [PATCH 21/55] Update unit test for applicationDidFinishLaunching change --- .../MSAppDelegateForwarderTests.m | 43 +---------- .../MobileCenterPush/Internal/MSPushPrivate.h | 5 ++ .../MobileCenterPushTests/MSPushTests.m | 75 +++++++------------ 3 files changed, 34 insertions(+), 89 deletions(-) diff --git a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m index 4034969d3a..335e0d8df2 100644 --- a/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m +++ b/MobileCenter/MobileCenterTests/MSAppDelegateForwarderTests.m @@ -1019,48 +1019,7 @@ - (void)testOpenURLForwardMethodNotImplementedByOriginalDelegate { } #endif -#if TARGET_OS_OSX -- (void)testDidReceiveNotification { - - // If - id userNotificationUserInfoMock = OCMClassMock([NSUserNotification class]); - id notificationMock = OCMClassMock([NSNotification class]); - NSDictionary *notificationUserInfo = @{NSApplicationLaunchUserNotificationKey : userNotificationUserInfoMock}; - NSDictionary *expectedUserInfo = @{ @"aKey" : @"aThingBehindADoor" }; - OCMStub([notificationMock userInfo]).andReturn(notificationUserInfo); - OCMStub([userNotificationUserInfoMock userInfo]).andReturn(expectedUserInfo); - XCTestExpectation *customCalledExpectation = [self expectationWithDescription:@"Custom delegate called."]; - - // Setup an empty original delegate. - id originalAppDelegate = - [self createInstanceConformingToProtocol:@protocol(MSApplicationDelegate)]; - SEL applicationDidFinishLaunchingSel = @selector(applicationDidFinishLaunching:); - [MSAppDelegateForwarder addAppDelegateSelectorToSwizzle:applicationDidFinishLaunchingSel]; - - // Setup a custom delegate. - id customAppDelegate = [self createInstanceConformingToProtocol:@protocol(MSAppDelegate)]; - id applicationDidFinishLaunchingImp = ^(__attribute__((unused)) id itSelf, NSNotification *notification) { - - // Then - XCTAssertNotNil(notification); - NSUserNotification *userNotification = [notification.userInfo objectForKey:NSApplicationLaunchUserNotificationKey]; - XCTAssertNotNil(userNotification); - assertThat(userNotification.userInfo, is(expectedUserInfo)); - [customCalledExpectation fulfill]; - }; - [self addSelector:applicationDidFinishLaunchingSel - implementation:applicationDidFinishLaunchingImp - toInstance:customAppDelegate]; - [MSAppDelegateForwarder swizzleOriginalDelegate:originalAppDelegate]; - [MSAppDelegateForwarder addDelegate:customAppDelegate]; - - // When - [originalAppDelegate applicationDidFinishLaunching:notificationMock]; - - // Then - [self waitForExpectations:@[ customCalledExpectation ] timeout:1]; -} -#elif TARGET_OS_IOS +#if TARGET_OS_IOS // TODO: Push doesn't support tvOS. Temporaily disable the test. - (void)testDidReceiveRemoteNotification { diff --git a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h index 6962579689..687ece6f75 100644 --- a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h +++ b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h @@ -43,4 +43,9 @@ */ - (void)registerForRemoteNotifications; +/** + * Observer to register user notification center delegate when application launches. + */ +- (void)applicationDidFinishLaunching:(NSNotification *)notification; + @end diff --git a/MobileCenterPush/MobileCenterPushTests/MSPushTests.m b/MobileCenterPush/MobileCenterPushTests/MSPushTests.m index 41b7015333..1d8647c64b 100644 --- a/MobileCenterPush/MobileCenterPushTests/MSPushTests.m +++ b/MobileCenterPush/MobileCenterPushTests/MSPushTests.m @@ -36,8 +36,6 @@ - (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken; - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; #if TARGET_OS_OSX -- (BOOL)didReceiveNotification:(NSNotification *)notification; - - (BOOL)didReceiveUserNotification:(NSUserNotification *)notification; #endif @@ -190,9 +188,9 @@ - (void)testNotificationReceivedWithAlertObject { OCMStub([userNotificationUserInfoMock userInfo]).andReturn(userInfo); #endif - // When +// When #if TARGET_OS_OSX - BOOL result = [MSPush didReceiveNotification:notificationMock]; + [self.sut applicationDidFinishLaunching:notificationMock]; #else BOOL result = [MSPush didReceiveRemoteNotification:userInfo]; #endif @@ -204,7 +202,7 @@ - (void)testNotificationReceivedWithAlertObject { [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { #if TARGET_OS_OSX - OCMVerify([pushMock didReceiveNotification:notificationMock]); + OCMVerify([pushMock didReceiveUserNotification:userNotificationUserInfoMock]); #else OCMVerify([pushMock didReceiveRemoteNotification:userInfo]); #endif @@ -217,7 +215,9 @@ - (void)testNotificationReceivedWithAlertObject { XCTFail(@"Expectation Failed with error: %@", error); } }]; +#if !TARGET_OS_OSX XCTAssertTrue(result); +#endif [pushMock stopMocking]; } @@ -245,9 +245,9 @@ - (void)testNotificationReceivedWithAlertString { OCMStub([userNotificationUserInfoMock userInfo]).andReturn(userInfo); #endif - // When +// When #if TARGET_OS_OSX - BOOL result = [MSPush didReceiveNotification:notificationMock]; + [self.sut applicationDidFinishLaunching:notificationMock]; #else BOOL result = [MSPush didReceiveRemoteNotification:userInfo]; #endif @@ -259,7 +259,7 @@ - (void)testNotificationReceivedWithAlertString { [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { #if TARGET_OS_OSX - OCMVerify([pushMock didReceiveNotification:notificationMock]); + OCMVerify([pushMock didReceiveUserNotification:userNotificationUserInfoMock]); #else OCMVerify([pushMock didReceiveRemoteNotification:userInfo]); #endif @@ -272,7 +272,9 @@ - (void)testNotificationReceivedWithAlertString { XCTFail(@"Expectation Failed with error: %@", error); } }]; +#if !TARGET_OS_OSX XCTAssertTrue(result); +#endif [pushMock stopMocking]; } @@ -302,11 +304,11 @@ - (void)testNotificationReceivedForNonMobileCenterNotification { // When #if TARGET_OS_OSX - BOOL result = [MSPush didReceiveNotification:notificationMock]; + [self.sut applicationDidFinishLaunching:notificationMock]; #else BOOL result = [MSPush didReceiveRemoteNotification:invalidUserInfo]; -#endif XCTAssertFalse(result); +#endif dispatch_async(dispatch_get_main_queue(), ^{ [notificationReceived fulfill]; }); @@ -314,7 +316,7 @@ - (void)testNotificationReceivedForNonMobileCenterNotification { // Then [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { - + // Then OCMVerifyAll(pushDelegateMock); XCTAssertNil(pushNotification); @@ -326,7 +328,7 @@ - (void)testNotificationReceivedForNonMobileCenterNotification { } - (void)testPushAppDelegateCallbacks { - + // If #if TARGET_OS_OSX id applicationMock = OCMClassMock([NSApplication class]); @@ -337,64 +339,43 @@ - (void)testPushAppDelegateCallbacks { OCMStub([pushMock sharedInstance]).andReturn(pushMock); [MSPush resetSharedInstance]; MSPushAppDelegate *delegate = [MSPushAppDelegate new]; - + // When id deviceTokenMock = OCMClassMock([NSData class]); [delegate application:applicationMock didRegisterForRemoteNotificationsWithDeviceToken:deviceTokenMock]; - + // Then OCMVerify([pushMock didRegisterForRemoteNotificationsWithDeviceToken:deviceTokenMock]); - + // When id errorMock = OCMClassMock([NSError class]); [delegate application:applicationMock didFailToRegisterForRemoteNotificationsWithError:errorMock]; - + // Then OCMVerify([pushMock didFailToRegisterForRemoteNotificationsWithError:errorMock]); - + // When id userInfoMock = OCMClassMock([NSDictionary class]); [delegate application:applicationMock didReceiveRemoteNotification:userInfoMock]; - + // Then OCMVerify([pushMock didReceiveRemoteNotification:userInfoMock]); - + #if !TARGET_OS_OSX - + // When XCTestExpectation *notificationReceived = [self expectationWithDescription:@"Valid notification received."]; - [delegate application:applicationMock didReceiveRemoteNotification:userInfoMock fetchCompletionHandler:^(__unused UIBackgroundFetchResult result) { - [notificationReceived fulfill]; - }]; - + [delegate application:applicationMock + didReceiveRemoteNotification:userInfoMock + fetchCompletionHandler:^(__unused UIBackgroundFetchResult result) { + [notificationReceived fulfill]; + }]; + // Then OCMVerify([pushMock didReceiveRemoteNotification:userInfoMock]); [self waitForExpectations:@[ notificationReceived ] timeout:0]; - #endif - -#if TARGET_OS_OSX - - // If - id userNotificationCenterMock = OCMClassMock([NSUserNotificationCenter class]); - OCMStub([userNotificationCenterMock defaultUserNotificationCenter]).andReturn(userNotificationCenterMock); - id notificationMock = OCMClassMock([NSNotification class]); - - // When - [delegate applicationDidFinishLaunching:notificationMock]; - - // Then - OCMVerify([userNotificationCenterMock setDelegate:delegate]); - OCMVerify([pushMock didReceiveNotification:notificationMock]); - // When - [delegate userNotificationCenter:userNotificationCenterMock didActivateNotification: notificationMock]; - - // Then - OCMVerify([pushMock didReceiveUserNotification:notificationMock]); - -#endif - [pushMock stopMocking]; } From 03256b338988b23a86a3f07f2e0ec3629f23bc2d Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 12:38:43 -0700 Subject: [PATCH 22/55] Remove custom code signing configuration on targets for SasquatchMac --- SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj index 0d919d2e92..290d894374 100644 --- a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj +++ b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj @@ -516,7 +516,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -536,7 +535,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -556,7 +554,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -575,7 +572,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; From f22e83b4eb31cc56331371258e43cdba42b9d418 Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 14:08:47 -0700 Subject: [PATCH 23/55] Expose trackModelException --- .../MobileCenterCrashes/MSCrashes.mm | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm index 7be6b47c62..280a733ce5 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm @@ -12,6 +12,7 @@ #import "MSServiceAbstractProtected.h" #import "MSWrapperExceptionManagerInternal.h" #import "MSWrapperCrashesHelper.h" +#import "MSHandledErrorLog.h" /** * Service name for initialization. @@ -243,6 +244,18 @@ + (void)setDelegate:(_Nullable id)delegate { [[self sharedInstance] setDelegate:delegate]; } +/* + * Track handled exception directly as model form. + * This API is not public and is used by wrapper SDKs. + */ ++ (void)trackModelException:(MSException *)exception { + @synchronized(self) { + if ([[self sharedInstance] canBeUsed]) { + [[self sharedInstance] trackModelException:exception]; + } + } +} + #pragma mark - Service initialization - (instancetype)init { @@ -1016,4 +1029,21 @@ + (BOOL)validatePropertiesForAttachment:(MSErrorAttachmentLog *)attachment { return errorIdValid && attachmentIdValid && attachmentDataValid && contentTypeValid; } +#pragma mark - Handled exceptions + +- (void)trackModelException:(MSException *)exception { + if (![self isEnabled]) + return; + + // Create an error log. + MSHandledErrorLog *log = [MSHandledErrorLog new]; + + // Set properties of the error log. + log.errorId = MS_UUID_STRING; + log.exception = exception; + + // Send log to log manager. + [self.logManager processLog:log forGroupId:self.groupId]; +} + @end From fbba75a05cd98e8d63ae1141e4b4d7dd848d0a44 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 14:28:25 -0700 Subject: [PATCH 24/55] Fix comile error on non-macOS platforms --- MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h index 687ece6f75..14d04df6e9 100644 --- a/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h +++ b/MobileCenterPush/MobileCenterPush/Internal/MSPushPrivate.h @@ -43,9 +43,11 @@ */ - (void)registerForRemoteNotifications; +#if TARGET_OS_OSX /** * Observer to register user notification center delegate when application launches. */ - (void)applicationDidFinishLaunching:(NSNotification *)notification; +#endif @end From fc205afc220f464e4ff7e2026ee4bc5caa80532b Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 14:47:40 -0700 Subject: [PATCH 25/55] Remove unnecessary public API for macOS Push --- MobileCenterPush/MobileCenterPush/MSPush.h | 11 ----------- MobileCenterPush/MobileCenterPush/MSPush.m | 8 +------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/MobileCenterPush/MobileCenterPush/MSPush.h b/MobileCenterPush/MobileCenterPush/MSPush.h index bba784fe48..bf7dec4392 100644 --- a/MobileCenterPush/MobileCenterPush/MSPush.h +++ b/MobileCenterPush/MobileCenterPush/MSPush.h @@ -22,17 +22,6 @@ NS_ASSUME_NONNULL_BEGIN */ + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; -#if TARGET_OS_OSX -/** - * Callback for notification with user notification on macOS. - * - * @param notification The received user notification. - * - * @return YES if the notification was sent via Mobile Center. - */ -+ (BOOL)didReceiveUserNotification:(NSUserNotification *)notification; -#endif - /** * Callback for notification with user info. * diff --git a/MobileCenterPush/MobileCenterPush/MSPush.m b/MobileCenterPush/MobileCenterPush/MSPush.m index 791afae7bf..fbeefdb604 100644 --- a/MobileCenterPush/MobileCenterPush/MSPush.m +++ b/MobileCenterPush/MobileCenterPush/MSPush.m @@ -97,12 +97,6 @@ + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { [[self sharedInstance] didFailToRegisterForRemoteNotificationsWithError:error]; } -#if TARGET_OS_OSX -+ (BOOL)didReceiveUserNotification:(NSUserNotification *)notification { - return [[self sharedInstance] didReceiveUserNotification:notification]; -} -#endif - + (BOOL)didReceiveRemoteNotification:(NSDictionary *)userInfo { return [[self sharedInstance] didReceiveRemoteNotification:userInfo fromUserNotification:NO]; } @@ -227,7 +221,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification { - (void)userNotificationCenter:(NSUserNotificationCenter *)__unused center didActivateNotification:(NSUserNotification *)notification { - [MSPush didReceiveUserNotification:notification]; + [self didReceiveUserNotification:notification]; } #endif From 1b214e6a757ced676474b57a54e227cc2c9828af Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 14:48:16 -0700 Subject: [PATCH 26/55] Add tests for handled error log --- .../Internals/MSCrashesInternal.h | 6 ++++ .../MSCrashesTests.mm | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h index 807fa7cd8a..86d7a88c30 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h @@ -23,4 +23,10 @@ */ - (void)configureCrashReporterWithUncaughtExceptionHandlerEnabled:(BOOL)enableUncaughtExceptionHandler; +/* + * Track handled exception directly as model form. + * This API is not public and is used by wrapper SDKs. + */ ++ (void)trackModelException:(MSException *)exception; + @end diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index 0f976deb31..e4f42c070a 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -18,6 +18,7 @@ #import "MSTestFrameworks.h" #import "MSWrapperExceptionManagerInternal.h" #import "MSWrapperCrashesHelper.h" +#import "MSHandledErrorLog.h" @class MSMockCrashesDelegate; @@ -25,6 +26,7 @@ static NSString *const kMSCrashesServiceName = @"Crashes"; static NSString *const kMSFatal = @"fatal"; static unsigned int kMaxAttachmentsPerCrashReport = 2; +static NSString *const kMSTypeHandledError = @"handled_error"; @interface MSCrashes () @@ -579,6 +581,37 @@ - (void)testWarningMessageAboutTooManyErrorAttachments { XCTAssertTrue(warningMessageHasBeenPrinted); } +- (void)testTrackModelException { + + // If + __block NSString *type; + __block NSString *errorId; + __block MSException *exception; + id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); + OCMStub([logManagerMock processLog:[OCMArg isKindOfClass:[MSAbstractLog class]] forGroupId:OCMOCK_ANY]) + .andDo(^(NSInvocation *invocation) { + MSHandledErrorLog *log; + [invocation getArgument:&log atIndex:2]; + type = log.type; + errorId = log.errorId; + exception = log.exception; + }); + [MSMobileCenter configureWithAppSecret:kMSTestAppSecret]; + [[MSCrashes sharedInstance] startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; + + // When + MSException *expectedException = [MSException new]; + expectedException.message = @"Oh this is wrong..."; + expectedException.stackTrace = @"mock strace"; + expectedException.type = @"Some.Exception"; + [MSCrashes trackModelException:expectedException]; + + // Then + assertThat(type, is(kMSTypeHandledError)); + assertThat(errorId, notNilValue()); + assertThat(exception, is(expectedException)); +} + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" - (NSArray *)attachmentsWithCrashes:(MSCrashes *)crashes forErrorReport:(MSErrorReport *)errorReport { From 16077db754613d0f1e1744cfa12dfda1fb9beb19 Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 15:02:37 -0700 Subject: [PATCH 27/55] Fix mac/tvos compilation --- .../MobileCenterCrashes.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj index 96fd254834..375d034ab3 100644 --- a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj +++ b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj @@ -343,6 +343,8 @@ 9224468C1F62276C00E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; 9224468D1F62277400E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; 9224468E1F62277500E4034A /* MSHandledErrorLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446851F6222EC00E4034A /* MSHandledErrorLogTests.m */; }; + 9224468F1F634AD200E4034A /* MSHandledErrorLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446831F621F3A00E4034A /* MSHandledErrorLog.m */; }; + 922446901F634AD600E4034A /* MSHandledErrorLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 922446831F621F3A00E4034A /* MSHandledErrorLog.m */; }; B24F3F0F1D93368F00827213 /* MSErrorLogFormatterTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = B24F3F0E1D93368F00827213 /* MSErrorLogFormatterTests.mm */; }; B24F3F121D9341BC00827213 /* MSErrorLogFormatterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = B24F3F101D93417B00827213 /* MSErrorLogFormatterPrivate.h */; }; B2A0A71C1D9C2AE700729A58 /* MSCrashesTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A0A71B1D9C2AE700729A58 /* MSCrashesTestUtil.m */; }; @@ -1552,6 +1554,7 @@ files = ( 0485AFA11EAA887500C10CAF /* MSErrorReport.m in Sources */, 0485AFA21EAA887500C10CAF /* MSCrashesCXXExceptionHandler.mm in Sources */, + 9224468F1F634AD200E4034A /* MSHandledErrorLog.m in Sources */, 0485AFA31EAA887500C10CAF /* MSAbstractErrorLog.m in Sources */, 0485AFA41EAA887500C10CAF /* MSException.m in Sources */, 0499F8751EDFAE1D00C3EDDA /* MSErrorAttachmentLog+Utility.m in Sources */, @@ -1600,6 +1603,7 @@ files = ( 04EBBEB21F01C0C90006B8AE /* MSErrorReport.m in Sources */, 04EBBEB31F01C0C90006B8AE /* MSCrashesCXXExceptionHandler.mm in Sources */, + 922446901F634AD600E4034A /* MSHandledErrorLog.m in Sources */, 04EBBEB41F01C0C90006B8AE /* MSAbstractErrorLog.m in Sources */, 04EBBEB51F01C0C90006B8AE /* MSException.m in Sources */, 04EBBEB61F01C0C90006B8AE /* MSErrorAttachmentLog+Utility.m in Sources */, From 643efd21cc89a683c0dc5bbb64b398deda93a168 Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 15:29:25 -0700 Subject: [PATCH 28/55] Fix some style issues --- .../project.pbxproj | 4 +- .../Internals/Model/MSHandledErrorLog.h | 6 +- .../MobileCenterCrashes/MSCrashes.mm | 6 +- .../MSCrashesTests.mm | 16 +- .../MSHandledErrorLogTests.m | 149 +++++++++--------- 5 files changed, 90 insertions(+), 91 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj index 375d034ab3..52831b7df4 100644 --- a/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj +++ b/MobileCenterCrashes/MobileCenterCrashes.xcodeproj/project.pbxproj @@ -993,13 +993,13 @@ 6E7D5C651D3E9321009EC9AC /* MSBinary.h */, 6E7D5C661D3E9321009EC9AC /* MSBinary.m */, 6E7D5C691D3E9332009EC9AC /* MSAppleErrorLog.h */, - 922446821F621D4500E4034A /* MSHandledErrorLog.h */, 6E7D5C6A1D3E9332009EC9AC /* MSAppleErrorLog.m */, + 922446821F621D4500E4034A /* MSHandledErrorLog.h */, + 922446831F621F3A00E4034A /* MSHandledErrorLog.m */, B2F120DF1D657CF10060DED7 /* MSErrorReport.m */, B2F120E61D657F4F0060DED7 /* MSErrorReportPrivate.h */, 6E7D5C711D3E9381009EC9AC /* MSThread.h */, 6E7D5C721D3E9381009EC9AC /* MSThread.m */, - 922446831F621F3A00E4034A /* MSHandledErrorLog.m */, ); path = Model; sourceTree = ""; diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h index 9e6c116773..99cf96b2fb 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.h @@ -3,17 +3,17 @@ @class MSException; -/* +/** * Handled Error log for managed platforms (such as Xamarin, Unity, Android Dalvik/ART). */ @interface MSHandledErrorLog : MSAbstractLog -/* +/** * Unique identifier for this error. */ @property(nonatomic, copy) NSString *errorId; -/* +/** * The exception. */ @property(nonatomic) MSException *exception; diff --git a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm index 280a733ce5..af5c3237c0 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm +++ b/MobileCenterCrashes/MobileCenterCrashes/MSCrashes.mm @@ -8,11 +8,11 @@ #import "MSErrorAttachmentLog.h" #import "MSErrorAttachmentLogInternal.h" #import "MSErrorLogFormatter.h" +#import "MSHandledErrorLog.h" #import "MSMobileCenterInternal.h" #import "MSServiceAbstractProtected.h" #import "MSWrapperExceptionManagerInternal.h" #import "MSWrapperCrashesHelper.h" -#import "MSHandledErrorLog.h" /** * Service name for initialization. @@ -230,7 +230,7 @@ + (MSErrorReport *_Nullable)lastSessionCrashReport { return [[self sharedInstance] getLastSessionCrashReport]; } -/* +/** * This can never be bound to Xamarin. * * This method is not part of the publicly available APIs on tvOS as Mach exception handling is not possible on tvOS. @@ -244,7 +244,7 @@ + (void)setDelegate:(_Nullable id)delegate { [[self sharedInstance] setDelegate:delegate]; } -/* +/** * Track handled exception directly as model form. * This API is not public and is used by wrapper SDKs. */ diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index e4f42c070a..6ecff727ee 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -25,8 +25,8 @@ static NSString *const kMSTestAppSecret = @"TestAppSecret"; static NSString *const kMSCrashesServiceName = @"Crashes"; static NSString *const kMSFatal = @"fatal"; -static unsigned int kMaxAttachmentsPerCrashReport = 2; static NSString *const kMSTypeHandledError = @"handled_error"; +static unsigned int kMaxAttachmentsPerCrashReport = 2; @interface MSCrashes () @@ -589,13 +589,13 @@ - (void)testTrackModelException { __block MSException *exception; id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); OCMStub([logManagerMock processLog:[OCMArg isKindOfClass:[MSAbstractLog class]] forGroupId:OCMOCK_ANY]) - .andDo(^(NSInvocation *invocation) { - MSHandledErrorLog *log; - [invocation getArgument:&log atIndex:2]; - type = log.type; - errorId = log.errorId; - exception = log.exception; - }); + .andDo(^(NSInvocation *invocation) { + MSHandledErrorLog *log; + [invocation getArgument:&log atIndex:2]; + type = log.type; + errorId = log.errorId; + exception = log.exception; + }); [MSMobileCenter configureWithAppSecret:kMSTestAppSecret]; [[MSCrashes sharedInstance] startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m b/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m index 9f14c5f3e1..eb69450039 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSHandledErrorLogTests.m @@ -1,6 +1,6 @@ -#import "MSHandledErrorLog.h" #import "MSCrashesTestUtil.h" #import "MSException.h" +#import "MSHandledErrorLog.h" #import "MSTestFrameworks.h" @interface MSHandledErrorLogTests : XCTestCase @@ -14,9 +14,8 @@ @implementation MSHandledErrorLogTests #pragma mark - Housekeeping - (void)setUp { - [super setUp]; - - self.sut = [self handledErrorLog]; + [super setUp]; + self.sut = [self handledErrorLog]; } - (void)tearDown { @@ -26,100 +25,100 @@ - (void)tearDown { #pragma mark - Helper - (MSHandledErrorLog *)handledErrorLog { - - MSHandledErrorLog *handledErrorLog = [MSHandledErrorLog new]; - handledErrorLog.type = @"handled_error"; - handledErrorLog.exception = [MSCrashesTestUtil exception]; - handledErrorLog.errorId = @"123"; - - return handledErrorLog; + MSHandledErrorLog *handledErrorLog = [MSHandledErrorLog new]; + handledErrorLog.type = @"handled_error"; + handledErrorLog.exception = [MSCrashesTestUtil exception]; + handledErrorLog.errorId = @"123"; + return handledErrorLog; } #pragma mark - Tests - (void)testInitializationWorks { - XCTAssertNotNil(self.sut); + XCTAssertNotNil(self.sut); } - (void)testSerializationToDictionaryWorks { - NSDictionary *actual = [self.sut serializeToDictionary]; - XCTAssertNotNil(actual); - assertThat(actual[@"type"], equalTo(self.sut.type)); - assertThat(actual[@"id"], equalTo(self.sut.errorId)); - - // Exception fields. - NSDictionary *exceptionDictionary = actual[@"exception"]; - XCTAssertNotNil(exceptionDictionary); - assertThat(exceptionDictionary[@"type"], equalTo(self.sut.exception.type)); - assertThat(exceptionDictionary[@"message"], equalTo(self.sut.exception.message)); - assertThat(exceptionDictionary[@"wrapper_sdk_name"], equalTo(self.sut.exception.wrapperSdkName)); + + // When + NSDictionary *actual = [self.sut serializeToDictionary]; + + // Then + XCTAssertNotNil(actual); + assertThat(actual[@"type"], equalTo(self.sut.type)); + assertThat(actual[@"id"], equalTo(self.sut.errorId)); + NSDictionary *exceptionDictionary = actual[@"exception"]; + XCTAssertNotNil(exceptionDictionary); + assertThat(exceptionDictionary[@"type"], equalTo(self.sut.exception.type)); + assertThat(exceptionDictionary[@"message"], equalTo(self.sut.exception.message)); + assertThat(exceptionDictionary[@"wrapper_sdk_name"], equalTo(self.sut.exception.wrapperSdkName)); } - (void)testNSCodingSerializationAndDeserializationWorks { - // When - NSData *serializedEvent = [NSKeyedArchiver archivedDataWithRootObject:self.sut]; - id actual = [NSKeyedUnarchiver unarchiveObjectWithData:serializedEvent]; - - // Then - assertThat(actual, notNilValue()); - assertThat(actual, instanceOf([MSHandledErrorLog class])); - - // The MSHandledErrorLog. - MSHandledErrorLog *actualLog = actual; - assertThat(actualLog, equalTo(self.sut)); - XCTAssertTrue([actualLog isEqual:self.sut]); - assertThat(actualLog.type, equalTo(self.sut.type)); - assertThat(actualLog.errorId, equalTo(self.sut.errorId)); - - // The exception field. - MSException *actualException = actualLog.exception; - assertThat(actualException.type, equalTo(self.sut.exception.type)); - assertThat(actualException.message, equalTo(self.sut.exception.message)); - assertThat(actualException.wrapperSdkName, equalTo(self.sut.exception.wrapperSdkName)); + // When + NSData *serializedEvent = [NSKeyedArchiver archivedDataWithRootObject:self.sut]; + id actual = [NSKeyedUnarchiver unarchiveObjectWithData:serializedEvent]; + + // Then + assertThat(actual, notNilValue()); + assertThat(actual, instanceOf([MSHandledErrorLog class])); + + // The MSHandledErrorLog. + MSHandledErrorLog *actualLog = actual; + assertThat(actualLog, equalTo(self.sut)); + XCTAssertTrue([actualLog isEqual:self.sut]); + assertThat(actualLog.type, equalTo(self.sut.type)); + assertThat(actualLog.errorId, equalTo(self.sut.errorId)); + + // The exception field. + MSException *actualException = actualLog.exception; + assertThat(actualException.type, equalTo(self.sut.exception.type)); + assertThat(actualException.message, equalTo(self.sut.exception.message)); + assertThat(actualException.wrapperSdkName, equalTo(self.sut.exception.wrapperSdkName)); } - (void)testIsEqual { - // When - MSHandledErrorLog *first = [self handledErrorLog]; - MSHandledErrorLog *second = [self handledErrorLog]; + // When + MSHandledErrorLog *first = [self handledErrorLog]; + MSHandledErrorLog *second = [self handledErrorLog]; - // Then - XCTAssertTrue([first isEqual:second]); + // Then + XCTAssertTrue([first isEqual:second]); - // When - second.errorId = MS_UUID_STRING; + // When + second.errorId = MS_UUID_STRING; - // Then - XCTAssertFalse([first isEqual:second]); + // Then + XCTAssertFalse([first isEqual:second]); } - (void)testIsValid { - // When - MSHandledErrorLog *log = [MSHandledErrorLog new]; - log.device = OCMClassMock([MSDevice class]); - OCMStub([log.device isValid]).andReturn(YES); - log.sid = @"sid"; - log.timestamp = [NSDate dateWithTimeIntervalSince1970:42]; - log.errorId = @"errorId"; - log.sid = MS_UUID_STRING; - - // Then - XCTAssertFalse([log isValid]); - - // When - log.errorId = MS_UUID_STRING; - - // Then - XCTAssertFalse([log isValid]); - - // When - log.exception = [MSCrashesTestUtil exception]; - - // Then - XCTAssertTrue([log isValid]); + // When + MSHandledErrorLog *log = [MSHandledErrorLog new]; + log.device = OCMClassMock([MSDevice class]); + OCMStub([log.device isValid]).andReturn(YES); + log.sid = @"sid"; + log.timestamp = [NSDate dateWithTimeIntervalSince1970:42]; + log.errorId = @"errorId"; + log.sid = MS_UUID_STRING; + + // Then + XCTAssertFalse([log isValid]); + + // When + log.errorId = MS_UUID_STRING; + + // Then + XCTAssertFalse([log isValid]); + + // When + log.exception = [MSCrashesTestUtil exception]; + + // Then + XCTAssertTrue([log isValid]); } @end From 6fc09ab8002ac0f4758adad5b6bef99296922463 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Fri, 8 Sep 2017 15:29:35 -0700 Subject: [PATCH 29/55] Revert "Remove custom code signing configuration on targets for SasquatchMac" This reverts commit 03256b338988b23a86a3f07f2e0ec3629f23bc2d. --- SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj index 290d894374..0d919d2e92 100644 --- a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj +++ b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj @@ -516,6 +516,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -535,6 +536,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -554,6 +556,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -572,6 +575,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; From 153c2c1be22bd8e59efa55e23c5b1c80860ce7ff Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 15:32:20 -0700 Subject: [PATCH 30/55] Sort imports --- .../MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m | 2 +- MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m index 7dca0859d2..524d325e3e 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/Model/MSHandledErrorLog.m @@ -1,5 +1,5 @@ -#import "MSHandledErrorLog.h" #import "MSException.h" +#import "MSHandledErrorLog.h" static NSString *const kMSTypeError = @"handled_error"; static NSString *const kMSId = @"id"; diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index 6ecff727ee..886e24ea87 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -9,6 +9,7 @@ #import "MSErrorAttachmentLogInternal.h" #import "MSErrorLogFormatter.h" #import "MSException.h" +#import "MSHandledErrorLog.h" #import "MSLogManagerDefault.h" #import "MSMobileCenter.h" #import "MSMobileCenterInternal.h" @@ -18,7 +19,6 @@ #import "MSTestFrameworks.h" #import "MSWrapperExceptionManagerInternal.h" #import "MSWrapperCrashesHelper.h" -#import "MSHandledErrorLog.h" @class MSMockCrashesDelegate; From 48a9b40596b3308090837c096546b4768a8758cf Mon Sep 17 00:00:00 2001 From: Guillaume Perrot Date: Fri, 8 Sep 2017 17:09:39 -0700 Subject: [PATCH 31/55] Don't test via static method --- .../MobileCenterCrashes/Internals/MSCrashesInternal.h | 2 +- .../MobileCenterCrashesTests/MSCrashesTests.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h index 86d7a88c30..2cb05211c6 100644 --- a/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h +++ b/MobileCenterCrashes/MobileCenterCrashes/Internals/MSCrashesInternal.h @@ -27,6 +27,6 @@ * Track handled exception directly as model form. * This API is not public and is used by wrapper SDKs. */ -+ (void)trackModelException:(MSException *)exception; +- (void)trackModelException:(MSException *)exception; @end diff --git a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm index 886e24ea87..33e91b803a 100644 --- a/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm +++ b/MobileCenterCrashes/MobileCenterCrashesTests/MSCrashesTests.mm @@ -597,14 +597,14 @@ - (void)testTrackModelException { exception = log.exception; }); [MSMobileCenter configureWithAppSecret:kMSTestAppSecret]; - [[MSCrashes sharedInstance] startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; + [self.sut startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; // When MSException *expectedException = [MSException new]; expectedException.message = @"Oh this is wrong..."; expectedException.stackTrace = @"mock strace"; expectedException.type = @"Some.Exception"; - [MSCrashes trackModelException:expectedException]; + [self.sut trackModelException:expectedException]; // Then assertThat(type, is(kMSTypeHandledError)); From 0c727aba4d28bda280c4dedd892ec5ee844e157a Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Mon, 11 Sep 2017 11:15:37 -0700 Subject: [PATCH 32/55] Address comments and formatting. --- .../MobileCenterDistribute/MSDistribute.m | 65 ++++++++++--------- .../MSDistributePrivate.h | 8 ++- .../MSDistributeTests.m | 20 ++++-- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index ff1a3fdb8d..bf4b98959b 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -214,7 +214,7 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { if (url) { /* - * Only iOS 9.x and 10.x will download the update after users click the "Install" button. + * Only iOS 9.x and 10.x will download the update after users click the "Install" button. * We need to force-exit the application for other versions or for any versions when the update is mandatory. */ #pragma clang diagnostic push @@ -222,22 +222,23 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { Class clazz = [SFSafariViewController class]; if (clazz && ![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11, 0, 0}]) { - // iOS 11 Class authClazz = [SFAuthenticationSession class]; - if(authClazz) { - + + // iOS 11 + if (authClazz) { + // Manipulate App UI on the main queue. dispatch_async(dispatch_get_main_queue(), ^{ [self openURLInAuthenticationSessionWith:url fromClass:authClazz]; }); } else { // iOS 9 and 10 - + // Manipulate App UI on the main queue. dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInEmbeddedSafari:url fromClass:clazz]; + [self openURLInSafariViewControllerWithUrl:url fromClass:clazz]; }); - } + } #pragma clang diagnostic pop } else { @@ -456,34 +457,36 @@ - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret rele - (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFAuthenticationSession to open URL: %@", url); - + NSString *callbackUrlScheme = [NSString stringWithFormat:kMSDefaultCustomSchemeFormat, self.appSecret]; - + if (@available(iOS 11.0, *)) { - SFAuthenticationSession *session = [[clazz alloc] initWithURL:url callbackURLScheme:callbackUrlScheme completionHandler:^(NSURL *callbackUrl, NSError *error) { - - self.authenticationSession = nil; - MSLogDebug([MSDistribute logTag], @"Called %@ with errror: %@", callbackUrl, error.localizedDescription); - - if(error.code == SFAuthenticationErrorCanceledLogin) { - MSLogError([MSDistribute logTag], @"Authentication session was cancelled by user or failed."); - } - - if(callbackUrl) { - [self openURL:callbackUrl]; - } - }]; + SFAuthenticationSession *session = [[clazz alloc] + initWithURL:url + callbackURLScheme:callbackUrlScheme + completionHandler:^(NSURL *callbackUrl, NSError *error) { + + self.authenticationSession = nil; + if (error != nil) { + MSLogDebug([MSDistribute logTag], @"Called %@ with errror: %@", callbackUrl, error.localizedDescription); + } + if (error.code == SFAuthenticationErrorCanceledLogin) { + MSLogError([MSDistribute logTag], @"Authentication session was cancelled by user or failed."); + } + if (callbackUrl) { + [self openURL:callbackUrl]; + } + }]; self.authenticationSession = session; BOOL success = [session start]; - if(success) { + if (success) { MSLogDebug([MSDistribute logTag], @"Authentication Session Started, showing confirmation dialog"); } } } -// TODO: rename method -- (void)openURLInEmbeddedSafari:(NSURL *)url fromClass:(Class)clazz { +- (void)openURLInSafariViewControllerWithUrl:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFSafariViewController to open URL: %@", url); // Init safari controller with the install URL. @@ -593,13 +596,13 @@ - (BOOL)handleUpdate:(MSReleaseDetails *)details { } - (BOOL)checkForUpdatesAllowed { - -// Check if we are not in AppStore or TestFlight environments. -BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; -// Check if a debugger is attached. -BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; -return environmentOkay && noDebuggerAttached; + // Check if we are not in AppStore or TestFlight environments. + BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; + + // Check if a debugger is attached. + BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; + return environmentOkay && noDebuggerAttached; } - (BOOL)isNewerVersion:(MSReleaseDetails *)details { diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h index 3877c34cab..5cbc49ab7a 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h @@ -132,12 +132,12 @@ static NSString *const kMSDistributionGroupIdKey = @"MSDistributionGroupId"; - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret releaseHash:(NSString *)releaseHash; /** - * Open the given URL using an `SFSafariViewController`. Must run on the UI thread! iOS 9+ only. + * Open the given URL using an `SFSafariViewController`. Must run on the UI thread! iOS 9 and 10 only. * * @param url URL to open. * @param clazz `SFSafariViewController` class. */ -- (void)openURLInEmbeddedSafari:(NSURL *)url fromClass:(Class)clazz; +- (void)openURLInSafariViewControllerWithUrl:(NSURL *)url fromClass:(Class)clazz; /** * Open the given URL using the Safari application. iOS 8.x only. @@ -162,7 +162,9 @@ static NSString *const kMSDistributionGroupIdKey = @"MSDistributionGroupId"; * @param distributionGroupId The distribution group Id in keychain. * @param releaseHash The release hash of the current version. */ -- (void)checkLatestRelease:(nullable NSString *)updateToken distributionGroupId:(NSString *)distributionGroupId releaseHash:(NSString *)releaseHash; +- (void)checkLatestRelease:(nullable NSString *)updateToken + distributionGroupId:(NSString *)distributionGroupId + releaseHash:(NSString *)releaseHash; /** * Send a request to get information for installation. diff --git a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m index 95501fcf70..8767332165 100644 --- a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m +++ b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m @@ -38,7 +38,7 @@ - (instancetype)initWithURL:(NSURL *)url; @implementation SFSafariViewController - (instancetype)initWithURL:(NSURL *)url { - if ((self = [super init])) { + if ((self = [self init])) { [[self class] setUrl:url]; } return self; @@ -130,7 +130,7 @@ - (void)testInstallURL { OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleURLTypes"]).andReturn(bundleArray); OCMStub([self.bundleMock objectForInfoDictionaryKey:@"MSAppName"]).andReturn(@"Something"); id distributeMock = OCMPartialMock(self.sut); - OCMStub([distributeMock openURLInEmbeddedSafari:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); + OCMStub([distributeMock openURLInSafariViewControllerWithUrl:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); // Disable for now to bypass initializing sender. [distributeMock setEnabled:NO]; @@ -222,14 +222,18 @@ - (void)testOpenURLInSafariApp { [appMock stopMocking]; } -- (void)testOpenURLInEmbeddedSafari { +- (void)testOpenURLInSafariViewControllerWithUrl { // If NSURL *url = [NSURL URLWithString:@"https://contoso.com"]; // When @try { - [self.sut openURLInEmbeddedSafari:url fromClass:[SFSafariViewController class]]; + if (@available(iOS 9.0, *)) { + [self.sut openURLInSafariViewControllerWithUrl:url fromClass:[SFSafariViewController class]]; + } else { + // Fallback on earlier versions + } } @catch (__attribute__((unused)) NSException *ex) { /** @@ -239,7 +243,11 @@ - (void)testOpenURLInEmbeddedSafari { } // Then - assertThat(SFSafariViewController.url, is(url)); + if (@available(iOS 9.0, *)) { + assertThat(SFSafariViewController.url, is(url)); + } else { + // Fallback on earlier versions + } } - (void)testSetApiUrlWorks { @@ -1196,7 +1204,7 @@ - (void)testWithoutNetwork { OCMReject([distributeMock buildTokenRequestURLWithAppSecret:OCMOCK_ANY releaseHash:kMSTestReleaseHash]); // We should not touch UI in a unit testing environment. - OCMStub([distributeMock openURLInEmbeddedSafari:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); + OCMStub([distributeMock openURLInSafariViewControllerWithUrl:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); // When [distributeMock requestInstallInformationWith:kMSTestReleaseHash]; From ab94cd3846316cdf0fc97587196d401be6750f96 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Mon, 11 Sep 2017 11:35:04 -0700 Subject: [PATCH 33/55] Not using trace buffer if the buffer is already flushed --- .../AppDelegate/MSAppDelegateForwarder.m | 40 ++++++++++++++----- .../MSAppDelegateForwarderPrivate.h | 5 --- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 70e67c4944..4a6cf12825 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -28,12 +28,16 @@ static NSArray *_selectorsNotToOverride = nil; static NSDictionary *_deprecatedSelectors = nil; static NSMutableDictionary *_originalImplementations = nil; -static NSMutableArray *_traceBuffer = nil; +static NSMutableArray *traceBuffer = nil; static IMP _originalSetDelegateImp = NULL; static BOOL _enabled = YES; @implementation MSAppDelegateForwarder ++ (void)initialize { + traceBuffer = [NSMutableArray new]; +} + + (void)load { /* @@ -50,11 +54,11 @@ + (void)load { // Swizzle `setDelegate:` of Application class. if (MSAppDelegateForwarder.enabled) { - [MSAppDelegateForwarder.traceBuffer addObject:^{ + [self addTraceBlock:^{ MSLogDebug([MSMobileCenter logTag], @"Application delegate forwarder is enabled. It may use swizzling."); }]; } else { - [MSAppDelegateForwarder.traceBuffer addObject:^{ + [self addTraceBlock:^{ MSLogDebug([MSMobileCenter logTag], @"Application delegate forwarder is disabled. It won't use swizzling."); }]; } @@ -107,8 +111,20 @@ + (void)setDelegates:(NSHashTable> *)delegates { return _originalImplementations ?: (_originalImplementations = [NSMutableDictionary new]); } -+ (NSMutableArray *)traceBuffer { - return _traceBuffer ?: (_traceBuffer = [NSMutableArray new]); ++ (void)addTraceBlock:(void (^)())block { + @synchronized(traceBuffer) { + if (traceBuffer) { + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + [traceBuffer addObject:^{ + MSLogVerbose([MSMobileCenter logTag], @"Trace buffer started."); + }]; + }); + [traceBuffer addObject:block]; + } else { + block(); + } + } } + (IMP)originalSetDelegateImp { @@ -245,7 +261,7 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector // Validate swizzling. if (!skipped) { if (!originalImp && !methodAdded) { - [self.traceBuffer addObject:^{ + [self addTraceBlock:^{ NSString *message = [NSString stringWithFormat:@"Cannot swizzle selector '%@' of class '%@'.", originalSelectorStr, originalClass]; if (warningMsg) { @@ -255,7 +271,7 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector } }]; } else { - [self.traceBuffer addObject:^{ + [self addTraceBlock:^{ MSLogDebug([MSMobileCenter logTag], @"Selector '%@' of class '%@' is swizzled.", originalSelectorStr, originalClass); }]; @@ -518,10 +534,14 @@ + (void)flushTraceBuffer { // Only trace once. static dispatch_once_t traceOnceToken; dispatch_once(&traceOnceToken, ^{ - for (dispatch_block_t traceBlock in self.traceBuffer) { - traceBlock(); + @synchronized(traceBuffer) { + for (dispatch_block_t traceBlock in traceBuffer) { + traceBlock(); + } + [traceBuffer removeAllObjects]; + traceBuffer = nil; + MSLogVerbose([MSMobileCenter logTag], @"Flushed trace buffer."); } - [self.traceBuffer removeAllObjects]; }); } diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h index 056748c1ba..2aea189892 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarderPrivate.h @@ -31,11 +31,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, class, readonly) NSMutableDictionary *originalImplementations; -/** - * Trace buffer storing debbuging traces. - */ -@property(nonatomic, class, readonly) NSMutableArray *traceBuffer; - #if TARGET_OS_OSX /** * Hold the original @see NSApplication#setDelegate: implementation. From 1a81a26c3b789132671bb2ad9f0df81a14509aaf Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Mon, 11 Sep 2017 11:38:59 -0700 Subject: [PATCH 34/55] Fix crash in test application when it receives a push notification without title --- SasquatchMac/SasquatchMacObjC/AppDelegate.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SasquatchMac/SasquatchMacObjC/AppDelegate.m b/SasquatchMac/SasquatchMacObjC/AppDelegate.m index d464e89a7c..e2302dbae0 100644 --- a/SasquatchMac/SasquatchMacObjC/AppDelegate.m +++ b/SasquatchMac/SasquatchMacObjC/AppDelegate.m @@ -115,9 +115,10 @@ - (void)push:(MSPush *)push didReceivePushNotification:(MSPushNotification *)pus for (NSString *key in pushNotification.customData) { message = [NSString stringWithFormat:@"%@\n%@: %@", message, key, [pushNotification.customData objectForKey:key]]; } - MSAlertController *alertController = [MSAlertController alertControllerWithTitle:pushNotification.title - message:message - style:NSAlertStyleInformational]; + MSAlertController *alertController = [MSAlertController + alertControllerWithTitle:(pushNotification.title ? pushNotification.title : @"Push notification received") + message:message + style:NSAlertStyleInformational]; [alertController addActionWithTitle:@"OK" handler:^(){ }]; From 2042bea40769075f185a3a92344b4f8ba1956d04 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Mon, 11 Sep 2017 16:09:29 -0700 Subject: [PATCH 35/55] Address PR feedback --- .../Internals/AppDelegate/MSAppDelegateForwarder.m | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m index 4a6cf12825..486bd4f663 100644 --- a/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m +++ b/MobileCenter/MobileCenter/Internals/AppDelegate/MSAppDelegateForwarder.m @@ -117,7 +117,7 @@ + (void)addTraceBlock:(void (^)())block { static dispatch_once_t onceToken = 0; dispatch_once(&onceToken, ^{ [traceBuffer addObject:^{ - MSLogVerbose([MSMobileCenter logTag], @"Trace buffer started."); + MSLogVerbose([MSMobileCenter logTag], @"Start buffering traces."); }]; }); [traceBuffer addObject:block]; @@ -530,19 +530,16 @@ - (void)forwardInvocation:(NSInvocation *)invocation { #pragma mark - Logging + (void)flushTraceBuffer { - - // Only trace once. - static dispatch_once_t traceOnceToken; - dispatch_once(&traceOnceToken, ^{ + if (traceBuffer) { @synchronized(traceBuffer) { for (dispatch_block_t traceBlock in traceBuffer) { traceBlock(); } [traceBuffer removeAllObjects]; traceBuffer = nil; - MSLogVerbose([MSMobileCenter logTag], @"Flushed trace buffer."); + MSLogVerbose([MSMobileCenter logTag], @"Stop buffering traces, flushed."); } - }); + } } #pragma mark - Testing From 242dd32f92aa6453fa7c4d585e46e9bc87b5af41 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 12 Sep 2017 09:28:00 -0700 Subject: [PATCH 36/55] Address comments --- .../MobileCenterDistribute/MSDistribute.m | 39 ++++++++----------- .../MSDistributePrivate.h | 2 +- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index bf4b98959b..3fa7f02224 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -1,5 +1,4 @@ #import -#import #import "MSAppDelegateForwarder.h" #import "MSDistribute.h" @@ -212,39 +211,35 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { // Most failures here require an app update. Thus, it will be retried only on next App instance. url = [self buildTokenRequestURLWithAppSecret:self.appSecret releaseHash:releaseHash]; if (url) { - -/* - * Only iOS 9.x and 10.x will download the update after users click the "Install" button. - * We need to force-exit the application for other versions or for any versions when the update is mandatory. - */ + + /* + * Only iOS 9.x and 10.x will download the update after users click the "Install" button. + * We need to force-exit the application for other versions or for any versions when the update is mandatory. + */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" - Class clazz = [SFSafariViewController class]; - if (clazz && ![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11, 0, 0}]) { - - Class authClazz = [SFAuthenticationSession class]; - - // iOS 11 - if (authClazz) { - - // Manipulate App UI on the main queue. + if(@available(iOS 9.0, *)) { + Class clazz = [SFSafariViewController class]; + if(@available(iOS 11.0, *)) { + + // iOS 11 dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInAuthenticationSessionWith:url fromClass:authClazz]; + [self openURLInAuthenticationSessionWith:url fromClass:clazz]; }); - } else { + } + else { + // iOS 9 and 10 - - // Manipulate App UI on the main queue. dispatch_async(dispatch_get_main_queue(), ^{ [self openURLInSafariViewControllerWithUrl:url fromClass:clazz]; }); } -#pragma clang diagnostic pop - } else { - + } + else { // iOS 8.x. [self openURLInSafariApp:url]; } +#pragma clang diagnostic pop } } else { diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h index 5cbc49ab7a..e8fbb40d97 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h @@ -112,7 +112,7 @@ static NSString *const kMSDistributionGroupIdKey = @"MSDistributionGroupId"; #pragma clang diagnostic ignored "-Wpartial-availability" @property(nullable, nonatomic) SFAuthenticationSession *authenticationSession; #pragma clang diagnostic pop -#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#endif /** * Returns the singleton instance. Meant for testing/demo apps only. From 24f9e16ce2fdc3a8f8988f0c2083e3f417aecbfd Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 12 Sep 2017 11:07:03 -0700 Subject: [PATCH 37/55] Adding iOS 8 as a deployment target to fix issues when integrating in an Xcode 8 project --- MobileCenter/MobileCenter.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj index 14d9c589b5..ead78aecb9 100644 --- a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj +++ b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj @@ -2058,6 +2058,7 @@ "DEBUG=1", "$(inherited)", ); + IPHONEOS_DEPLOYMENT_TARGET = 8.0; }; name = Debug; }; @@ -2065,6 +2066,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 0469D1B11F4DF89A00A43A8E /* MobileCenter Release.xcconfig */; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 8.0; }; name = Release; }; From feb0c3c7c012c1615b0d8f1c25c2b25053020dc3 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 12 Sep 2017 11:49:30 -0700 Subject: [PATCH 38/55] Rename method & fix error when using SFAuthenticationSession. --- .../MobileCenterDistribute/MSDistribute.m | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index 3fa7f02224..a16b1b337f 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -211,31 +211,30 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { // Most failures here require an app update. Thus, it will be retried only on next App instance. url = [self buildTokenRequestURLWithAppSecret:self.appSecret releaseHash:releaseHash]; if (url) { - - /* - * Only iOS 9.x and 10.x will download the update after users click the "Install" button. - * We need to force-exit the application for other versions or for any versions when the update is mandatory. - */ + +/* + * Only iOS 9.x and 10.x will download the update after users click the "Install" button. + * We need to force-exit the application for other versions or for any versions when the update is mandatory. + */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" - if(@available(iOS 9.0, *)) { - Class clazz = [SFSafariViewController class]; - if(@available(iOS 11.0, *)) { - + if (@available(iOS 9.0, *)) { + if (@available(iOS 11.0, *)) { + // iOS 11 + Class clazz = [SFAuthenticationSession class]; dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInAuthenticationSessionWith:url fromClass:clazz]; + [self openURLInAuthenticationSession:url fromClass:clazz]; }); - } - else { - + } else { + // iOS 9 and 10 + Class clazz = [SFSafariViewController class]; dispatch_async(dispatch_get_main_queue(), ^{ [self openURLInSafariViewControllerWithUrl:url fromClass:clazz]; }); } - } - else { + } else { // iOS 8.x. [self openURLInSafariApp:url]; } @@ -450,7 +449,7 @@ - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret rele return components.URL; } -- (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { +- (void)openURLInAuthenticationSession:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFAuthenticationSession to open URL: %@", url); NSString *callbackUrlScheme = [NSString stringWithFormat:kMSDefaultCustomSchemeFormat, self.appSecret]; From 69132fbd0139acedae92f89e901c214b7a6dd8b1 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Wed, 13 Sep 2017 14:13:38 -0700 Subject: [PATCH 39/55] Fix compat with Xcode 8 --- .../MobileCenterDistribute/MSDistribute.m | 45 +++++++++++-------- .../MSDistributePrivate.h | 23 ++++++++-- .../MSDistributeTests.m | 16 ++----- 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index a16b1b337f..a9f4efe030 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -1,5 +1,5 @@ #import - +#import #import "MSAppDelegateForwarder.h" #import "MSDistribute.h" #import "MSDistributeAppDelegate.h" @@ -218,23 +218,32 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" - if (@available(iOS 9.0, *)) { + Class clazz = [SFSafariViewController class]; + if (clazz) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 if (@available(iOS 11.0, *)) { // iOS 11 - Class clazz = [SFAuthenticationSession class]; + Class authClazz = [SFAuthenticationSession class]; dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInAuthenticationSession:url fromClass:clazz]; + [self openURLInAuthenticationSessionWith:url fromClass:authClazz]; }); } else { - // iOS 9 and 10 - Class clazz = [SFSafariViewController class]; + // Compiling against iOS 11 but running on iOS 9 and 10. dispatch_async(dispatch_get_main_queue(), ^{ - [self openURLInSafariViewControllerWithUrl:url fromClass:clazz]; + [self openURLInSafariViewControllerWith:url fromClass:clazz]; }); } +#else + + // The app is not compiled against the iOS 11 SDK, use the logic for iOS 9 and 10. + dispatch_async(dispatch_get_main_queue(), ^{ + [self openURLInSafariViewControllerWith:url fromClass:clazz]; + }); +#endif } else { + // iOS 8.x. [self openURLInSafariApp:url]; } @@ -449,11 +458,10 @@ - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret rele return components.URL; } -- (void)openURLInAuthenticationSession:(NSURL *)url fromClass:(Class)clazz { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 +- (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFAuthenticationSession to open URL: %@", url); - NSString *callbackUrlScheme = [NSString stringWithFormat:kMSDefaultCustomSchemeFormat, self.appSecret]; - if (@available(iOS 11.0, *)) { SFAuthenticationSession *session = [[clazz alloc] initWithURL:url @@ -479,8 +487,9 @@ - (void)openURLInAuthenticationSession:(NSURL *)url fromClass:(Class)clazz { } } } +#endif -- (void)openURLInSafariViewControllerWithUrl:(NSURL *)url fromClass:(Class)clazz { +- (void)openURLInSafariViewControllerWith:(NSURL *)url fromClass:(Class)clazz { MSLogDebug([MSDistribute logTag], @"Using SFSafariViewController to open URL: %@", url); // Init safari controller with the install URL. @@ -590,13 +599,13 @@ - (BOOL)handleUpdate:(MSReleaseDetails *)details { } - (BOOL)checkForUpdatesAllowed { - - // Check if we are not in AppStore or TestFlight environments. - BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; - - // Check if a debugger is attached. - BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; - return environmentOkay && noDebuggerAttached; + return YES; + // // Check if we are not in AppStore or TestFlight environments. + // BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; + // + // // Check if a debugger is attached. + // BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; + // return environmentOkay && noDebuggerAttached; } - (BOOL)isNewerVersion:(MSReleaseDetails *)details { diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h index e8fbb40d97..33e1fd22fa 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h @@ -1,9 +1,16 @@ #import +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#ifndef __IPHONE_11_0 +#define __IPHONE_11_0 110000 +#endif +#pragma clang diagnostic pop + #import "MSAlertController.h" #import "MSUIAppDelegate.h" #import "MSDistribute.h" -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" #import @@ -107,7 +114,7 @@ static NSString *const kMSDistributionGroupIdKey = @"MSDistributionGroupId"; */ @property(nonatomic) id appDelegate; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" @property(nullable, nonatomic) SFAuthenticationSession *authenticationSession; @@ -131,13 +138,23 @@ static NSString *const kMSDistributionGroupIdKey = @"MSDistributionGroupId"; */ - (nullable NSURL *)buildTokenRequestURLWithAppSecret:(NSString *)appSecret releaseHash:(NSString *)releaseHash; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 +/** + * Open the given URL using an `SFAuthenticationSession`. Must run on the UI thread! iOS 11 only. + * + * @param url URL to open. + * @param clazz `SFAuthenticationSession` class. + */ +- (void)openURLInAuthenticationSessionWith:(NSURL *)url fromClass:(Class)clazz; +#endif + /** * Open the given URL using an `SFSafariViewController`. Must run on the UI thread! iOS 9 and 10 only. * * @param url URL to open. * @param clazz `SFSafariViewController` class. */ -- (void)openURLInSafariViewControllerWithUrl:(NSURL *)url fromClass:(Class)clazz; +- (void)openURLInSafariViewControllerWith:(NSURL *)url fromClass:(Class)clazz; /** * Open the given URL using the Safari application. iOS 8.x only. diff --git a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m index 8767332165..bc133ab65a 100644 --- a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m +++ b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m @@ -130,7 +130,7 @@ - (void)testInstallURL { OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleURLTypes"]).andReturn(bundleArray); OCMStub([self.bundleMock objectForInfoDictionaryKey:@"MSAppName"]).andReturn(@"Something"); id distributeMock = OCMPartialMock(self.sut); - OCMStub([distributeMock openURLInSafariViewControllerWithUrl:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); + OCMStub([distributeMock openURLInSafariViewControllerWith:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); // Disable for now to bypass initializing sender. [distributeMock setEnabled:NO]; @@ -229,11 +229,7 @@ - (void)testOpenURLInSafariViewControllerWithUrl { // When @try { - if (@available(iOS 9.0, *)) { - [self.sut openURLInSafariViewControllerWithUrl:url fromClass:[SFSafariViewController class]]; - } else { - // Fallback on earlier versions - } + [self.sut openURLInSafariViewControllerWith:url fromClass:[SFSafariViewController class]]; } @catch (__attribute__((unused)) NSException *ex) { /** @@ -243,11 +239,7 @@ - (void)testOpenURLInSafariViewControllerWithUrl { } // Then - if (@available(iOS 9.0, *)) { - assertThat(SFSafariViewController.url, is(url)); - } else { - // Fallback on earlier versions - } + assertThat(SFSafariViewController.url, is(url)); } - (void)testSetApiUrlWorks { @@ -1204,7 +1196,7 @@ - (void)testWithoutNetwork { OCMReject([distributeMock buildTokenRequestURLWithAppSecret:OCMOCK_ANY releaseHash:kMSTestReleaseHash]); // We should not touch UI in a unit testing environment. - OCMStub([distributeMock openURLInSafariViewControllerWithUrl:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); + OCMStub([distributeMock openURLInSafariViewControllerWith:OCMOCK_ANY fromClass:OCMOCK_ANY]).andDo(nil); // When [distributeMock requestInstallInformationWith:kMSTestReleaseHash]; From c3f69b47d6ce0d2549abc02554b33dc7856fd2f4 Mon Sep 17 00:00:00 2001 From: Murat Baysangurov Date: Thu, 14 Sep 2017 11:58:40 +0300 Subject: [PATCH 40/55] Push UI added to Puppet --- Puppet/Puppet.xcodeproj/project.pbxproj | 51 +++++++ Puppet/Puppet/Base.lproj/Main.storyboard | 186 ++++++++++++++++------- Puppet/Puppet/MSPushViewController.h | 9 ++ Puppet/Puppet/MSPushViewController.m | 26 ++++ 4 files changed, 215 insertions(+), 57 deletions(-) create mode 100644 Puppet/Puppet/MSPushViewController.h create mode 100644 Puppet/Puppet/MSPushViewController.m diff --git a/Puppet/Puppet.xcodeproj/project.pbxproj b/Puppet/Puppet.xcodeproj/project.pbxproj index 924b4e382f..2114c44676 100644 --- a/Puppet/Puppet.xcodeproj/project.pbxproj +++ b/Puppet/Puppet.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 5CE60DF11EDF0B670060303A /* MSCrashResultViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5CE60DF01EDF0B670060303A /* MSCrashResultViewController.m */; }; 6EC99A211D4151A00016C325 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EC99A201D4151A00016C325 /* CrashReporter.framework */; }; 6EC99A281D4152FA0016C325 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EC99A271D4152FA0016C325 /* libc++.tbd */; }; + 80493AB71F6A701900E6E895 /* MSPushViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80493AB61F6A701900E6E895 /* MSPushViewController.m */; }; 808A10FC1EF312A000DFD41B /* MSPropertiesTableDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 808A10F91EF312A000DFD41B /* MSPropertiesTableDataSource.m */; }; 808A10FD1EF312A000DFD41B /* MSPropertyViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 808A10FB1EF312A000DFD41B /* MSPropertyViewCell.m */; }; B21B26C71DDE490400FF0378 /* MSCrashesDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B21B26C61DDE490400FF0378 /* MSCrashesDetailViewController.m */; }; @@ -240,6 +241,27 @@ remoteGlobalIDString = E82E1B5E1D1CA58D00D281C1; remoteInfo = Puppet; }; + 80493AC31F6A701A00E6E895 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E82E1B821D1CA63000D281C1 /* MobileCenter.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF2B1F3B864600C8E338; + remoteInfo = MobileCenterTVOSTests; + }; + 80493AD01F6A701A00E6E895 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E85547FB1D2D6C8D002DF6E2 /* MobileCenterAnalytics.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF541F3B8E6300C8E338; + remoteInfo = MobileCenterAnalyticsTVOSTests; + }; + 80493ADD1F6A701A00E6E895 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E82E1B7C1D1CA62900D281C1 /* MobileCenterCrashes.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF9D1F3B977100C8E338; + remoteInfo = MobileCenterCrashesTVOSTests; + }; B2C070CA1E5F59A90076D6A9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0471B91E1E4550670022F951 /* MobileCenterDistribute.xcodeproj */; @@ -367,6 +389,8 @@ 6EC99A201D4151A00016C325 /* CrashReporter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporter.framework; path = ../../Vendor/PLCrashReporter/CrashReporter.framework; sourceTree = ""; }; 6EC99A251D4152EB0016C325 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 6EC99A271D4152FA0016C325 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; + 80493AB51F6A701900E6E895 /* MSPushViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSPushViewController.h; sourceTree = ""; }; + 80493AB61F6A701900E6E895 /* MSPushViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSPushViewController.m; sourceTree = ""; }; 808A10F81EF312A000DFD41B /* MSPropertiesTableDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MSPropertiesTableDataSource.h; path = ../../Vendor/Common/Utils/MSPropertiesTableDataSource.h; sourceTree = ""; }; 808A10F91EF312A000DFD41B /* MSPropertiesTableDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MSPropertiesTableDataSource.m; path = ../../Vendor/Common/Utils/MSPropertiesTableDataSource.m; sourceTree = ""; }; 808A10FA1EF312A000DFD41B /* MSPropertyViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MSPropertyViewCell.h; path = ../../Vendor/Common/Utils/MSPropertyViewCell.h; sourceTree = ""; }; @@ -613,6 +637,7 @@ 046AEAA91ECA509000CBE511 /* libMobileCenterCrashes.a */, 046AEAAB1ECA509000CBE511 /* MobileCenterCrashes.xctest */, 04EBBF1C1F01CCBE0006B8AE /* libMobileCenterCrashes.a */, + 80493ADE1F6A701A00E6E895 /* MobileCenterCrashes.xctest */, ); name = Products; sourceTree = ""; @@ -625,6 +650,7 @@ 046AEA9A1ECA509000CBE511 /* libMobileCenter.a */, 048494D11ECCD9E40020B0FC /* MobileCenter.xctest */, 04685E661EE776AC00A1592F /* libMobileCenter.a */, + 80493AC41F6A701A00E6E895 /* MobileCenter.xctest */, ); name = Products; sourceTree = ""; @@ -637,6 +663,7 @@ 046AEAA11ECA509000CBE511 /* libMobileCenterAnalytics.a */, 048494D91ECCD9E40020B0FC /* MobileCenterAnalytics.xctest */, 04685E701EE776AC00A1592F /* libMobileCenterAnalytics.a */, + 80493AD11F6A701A00E6E895 /* MobileCenterAnalytics.xctest */, ); name = Products; sourceTree = ""; @@ -668,6 +695,8 @@ B2E611F41DDE72BA00A9DF86 /* MSFakeCXXClass.mm */, E89E6A2A1D396D7900CAA2CD /* MSMainViewController.h */, E89E6A2B1D396D7900CAA2CD /* MSMainViewController.m */, + 80493AB51F6A701900E6E895 /* MSPushViewController.h */, + 80493AB61F6A701900E6E895 /* MSPushViewController.m */, ); name = Classes; sourceTree = ""; @@ -958,6 +987,27 @@ remoteRef = 04EBBF1B1F01CCBE0006B8AE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 80493AC41F6A701A00E6E895 /* MobileCenter.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenter.xctest; + remoteRef = 80493AC31F6A701A00E6E895 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 80493AD11F6A701A00E6E895 /* MobileCenterAnalytics.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenterAnalytics.xctest; + remoteRef = 80493AD01F6A701A00E6E895 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 80493ADE1F6A701A00E6E895 /* MobileCenterCrashes.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenterCrashes.xctest; + remoteRef = 80493ADD1F6A701A00E6E895 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; B2C070CB1E5F59A90076D6A9 /* MobileCenterDistributeResources.bundle */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; @@ -1077,6 +1127,7 @@ 808A10FC1EF312A000DFD41B /* MSPropertiesTableDataSource.m in Sources */, E89E6A301D39704900CAA2CD /* MSAnalyticsViewController.m in Sources */, E82E1B641D1CA58D00D281C1 /* main.m in Sources */, + 80493AB71F6A701900E6E895 /* MSPushViewController.m in Sources */, 808A10FD1EF312A000DFD41B /* MSPropertyViewCell.m in Sources */, BA6827C9F0410233C245D989 /* MSDistributeViewController.m in Sources */, 5CE60DF11EDF0B670060303A /* MSCrashResultViewController.m in Sources */, diff --git a/Puppet/Puppet/Base.lproj/Main.storyboard b/Puppet/Puppet/Base.lproj/Main.storyboard index d2266a0018..5619abf80a 100644 --- a/Puppet/Puppet/Base.lproj/Main.storyboard +++ b/Puppet/Puppet/Base.lproj/Main.storyboard @@ -1,15 +1,67 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29,7 +81,7 @@ + + @@ -820,7 +872,7 @@ - + @@ -855,7 +907,7 @@ - + @@ -878,7 +930,7 @@ - + @@ -911,7 +963,7 @@ - + @@ -964,7 +1016,7 @@ - + @@ -1021,7 +1073,7 @@ - + @@ -1065,7 +1117,7 @@ - + @@ -1112,7 +1164,7 @@ - + diff --git a/SasquatchMac/SasquatchMac/PushViewController.swift b/SasquatchMac/SasquatchMac/PushViewController.swift new file mode 100644 index 0000000000..784ec334cb --- /dev/null +++ b/SasquatchMac/SasquatchMac/PushViewController.swift @@ -0,0 +1,22 @@ +import Cocoa + +class PushViewController: NSViewController { + + var mobileCenter: MobileCenterDelegate? + + @IBOutlet weak var setEnabledButton: NSButton! + + override func viewDidLoad() { + super.viewDidLoad(); + mobileCenter = MobileCenterProvider.shared().mobileCenter; + } + + override func viewWillAppear() { + setEnabledButton?.state = mobileCenter!.isPushEnabled() ? 1 : 0; + } + + @IBAction func setEnabled(_ sender: NSButton) { + mobileCenter?.setPushEnabled(sender.state == 1) + sender.state = mobileCenter!.isPushEnabled() ? 1 : 0 + } +} From 83d768cd3e9567c784ca1e604cdad856f58d212e Mon Sep 17 00:00:00 2001 From: Murat Baysangurov Date: Thu, 14 Sep 2017 13:19:40 +0300 Subject: [PATCH 44/55] Move enabledButton state setup to viewWillAppear --- .../ViewControllers/AnalyticsViewController.swift | 5 ++++- .../SasquatchMac/ViewControllers/CrashesViewController.swift | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/SasquatchMac/SasquatchMac/ViewControllers/AnalyticsViewController.swift b/SasquatchMac/SasquatchMac/ViewControllers/AnalyticsViewController.swift index ecc9eff616..8f3b236cdc 100644 --- a/SasquatchMac/SasquatchMac/ViewControllers/AnalyticsViewController.swift +++ b/SasquatchMac/SasquatchMac/ViewControllers/AnalyticsViewController.swift @@ -20,13 +20,16 @@ class AnalyticsViewController : NSViewController, NSTableViewDataSource, NSTable override func viewDidLoad() { super.viewDidLoad(); mobileCenter = MobileCenterProvider.shared().mobileCenter; - setEnabledButton?.state = mobileCenter!.isAnalyticsEnabled() ? 1 : 0; table?.delegate = self; table?.dataSource = self; NotificationCenter.default.addObserver(self, selector: #selector(self.editingDidBegin), name: .NSControlTextDidBeginEditing, object: nil); NotificationCenter.default.addObserver(self, selector: #selector(self.editingDidEnd), name: .NSControlTextDidEndEditing, object: nil); } + override func viewWillAppear() { + setEnabledButton?.state = mobileCenter!.isAnalyticsEnabled() ? 1 : 0; + } + override func viewDidDisappear() { super.viewDidDisappear(); NotificationCenter.default.removeObserver(self); diff --git a/SasquatchMac/SasquatchMac/ViewControllers/CrashesViewController.swift b/SasquatchMac/SasquatchMac/ViewControllers/CrashesViewController.swift index f647b818b4..8dfae4b3d0 100644 --- a/SasquatchMac/SasquatchMac/ViewControllers/CrashesViewController.swift +++ b/SasquatchMac/SasquatchMac/ViewControllers/CrashesViewController.swift @@ -13,7 +13,10 @@ class CrashesViewController : NSViewController, NSTableViewDataSource, NSTableVi crashesTableView.dataSource = self crashesTableView.delegate = self mobileCenter = MobileCenterProvider.shared().mobileCenter - setEnabledButton?.state = mobileCenter!.isCrashesEnabled() ? 1 : 0 + } + + override func viewWillAppear() { + setEnabledButton?.state = mobileCenter!.isCrashesEnabled() ? 1 : 0; } @IBAction func setEnabled(sender : NSButton) { From 62f083211b02be669fd037be199061aeac805cd0 Mon Sep 17 00:00:00 2001 From: Murat Baysangurov Date: Thu, 14 Sep 2017 15:38:31 +0300 Subject: [PATCH 45/55] testApplyEnabledStateTrue test fixed by using MSKeychainUtil mock --- .../MobileCenterDistributeTests/MSDistributeTests.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m index 95501fcf70..30b3d77f73 100644 --- a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m +++ b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m @@ -1055,7 +1055,8 @@ - (void)testApplyEnabledStateTrue { OCMVerify([distributeMock requestInstallInformationWith:kMSTestReleaseHash]); // If, private distribution - [MSKeychainUtil storeString:@"UpdateToken" forKey:kMSUpdateTokenKey]; + id keychainUtilMock = OCMClassMock([MSKeychainUtil class]); + OCMStub([keychainUtilMock stringForKey:kMSUpdateTokenKey]).andReturn(@"UpdateToken"); [self.settingsMock setObject:@"DistributionGroupId" forKey:kMSDistributionGroupIdKey]; // When From 34db365bdb4c209e75aefbd80b54663189f09f67 Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Thu, 14 Sep 2017 15:55:30 -0700 Subject: [PATCH 46/55] Add silent notifications to apps + fix sasquatch ios swift not calling fetch handler --- Puppet/Puppet.xcodeproj/project.pbxproj | 48 +++++++++++++++++ Puppet/Puppet/AppDelegate.m | 51 ++++++++++--------- Puppet/Puppet/Info.plist | 34 +++++++------ Sasquatch/Sasquatch.xcodeproj/project.pbxproj | 6 +++ Sasquatch/SasquatchObjC/AppDelegate.m | 30 +++++++---- Sasquatch/SasquatchObjC/Info.plist | 17 ++----- Sasquatch/SasquatchSwift/AppDelegate.swift | 23 +++++++-- Sasquatch/SasquatchSwift/Info.plist | 8 ++- 8 files changed, 149 insertions(+), 68 deletions(-) diff --git a/Puppet/Puppet.xcodeproj/project.pbxproj b/Puppet/Puppet.xcodeproj/project.pbxproj index 924b4e382f..42972ec524 100644 --- a/Puppet/Puppet.xcodeproj/project.pbxproj +++ b/Puppet/Puppet.xcodeproj/project.pbxproj @@ -233,6 +233,27 @@ remoteGlobalIDString = 6E0401321D1C98690051BCFA; remoteInfo = MobileCenterCrashes; }; + 388CCA081F699BFF00780C59 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E82E1B821D1CA63000D281C1 /* MobileCenter.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF2B1F3B864600C8E338; + remoteInfo = MobileCenterTVOSTests; + }; + 388CCA151F699BFF00780C59 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E85547FB1D2D6C8D002DF6E2 /* MobileCenterAnalytics.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF541F3B8E6300C8E338; + remoteInfo = MobileCenterAnalyticsTVOSTests; + }; + 388CCA221F699BFF00780C59 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E82E1B7C1D1CA62900D281C1 /* MobileCenterCrashes.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0446DF9D1F3B977100C8E338; + remoteInfo = MobileCenterCrashesTVOSTests; + }; 5CE2583C1EA5097100DA8FB9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E82E1B571D1CA58D00D281C1 /* Project object */; @@ -613,6 +634,7 @@ 046AEAA91ECA509000CBE511 /* libMobileCenterCrashes.a */, 046AEAAB1ECA509000CBE511 /* MobileCenterCrashes.xctest */, 04EBBF1C1F01CCBE0006B8AE /* libMobileCenterCrashes.a */, + 388CCA231F699BFF00780C59 /* MobileCenterCrashes.xctest */, ); name = Products; sourceTree = ""; @@ -625,6 +647,7 @@ 046AEA9A1ECA509000CBE511 /* libMobileCenter.a */, 048494D11ECCD9E40020B0FC /* MobileCenter.xctest */, 04685E661EE776AC00A1592F /* libMobileCenter.a */, + 388CCA091F699BFF00780C59 /* MobileCenter.xctest */, ); name = Products; sourceTree = ""; @@ -637,6 +660,7 @@ 046AEAA11ECA509000CBE511 /* libMobileCenterAnalytics.a */, 048494D91ECCD9E40020B0FC /* MobileCenterAnalytics.xctest */, 04685E701EE776AC00A1592F /* libMobileCenterAnalytics.a */, + 388CCA161F699BFF00780C59 /* MobileCenterAnalytics.xctest */, ); name = Products; sourceTree = ""; @@ -788,6 +812,9 @@ DevelopmentTeam = L4RARDNZ2Y; ProvisioningStyle = Manual; SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 1; + }; com.apple.Push = { enabled = 1; }; @@ -958,6 +985,27 @@ remoteRef = 04EBBF1B1F01CCBE0006B8AE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 388CCA091F699BFF00780C59 /* MobileCenter.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenter.xctest; + remoteRef = 388CCA081F699BFF00780C59 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 388CCA161F699BFF00780C59 /* MobileCenterAnalytics.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenterAnalytics.xctest; + remoteRef = 388CCA151F699BFF00780C59 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 388CCA231F699BFF00780C59 /* MobileCenterCrashes.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MobileCenterCrashes.xctest; + remoteRef = 388CCA221F699BFF00780C59 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; B2C070CB1E5F59A90076D6A9 /* MobileCenterDistributeResources.bundle */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; diff --git a/Puppet/Puppet/AppDelegate.m b/Puppet/Puppet/AppDelegate.m index c9cdbb102e..0c07cc2d9e 100644 --- a/Puppet/Puppet/AppDelegate.m +++ b/Puppet/Puppet/AppDelegate.m @@ -29,7 +29,8 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // View controller should register in NSNotificationCenter before SDK start. - crashResultViewController = [[[[self window] rootViewController] storyboard] instantiateViewControllerWithIdentifier:@"crashResult"]; + crashResultViewController = + [[[[self window] rootViewController] storyboard] instantiateViewControllerWithIdentifier:@"crashResult"]; // Customize Mobile Center SDK. [MSDistribute setDelegate:self]; @@ -123,8 +124,7 @@ - (void)crashes { [MSCrashes setDelegate:self]; [MSCrashes setUserConfirmationHandler:(^(NSArray *errorReports) { - [NSNotificationCenter.defaultCenter postNotificationName:kDidShouldAwaitUserConfirmationEvent - object:nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kDidShouldAwaitUserConfirmationEvent object:nil]; // Show a dialog to the user where they can choose if they want to provide a crash report. MSAlertController *alertController = [MSAlertController @@ -158,27 +158,23 @@ - (void)crashes { #pragma mark - MSCrashesDelegate - (BOOL)crashes:(MSCrashes *)crashes shouldProcessErrorReport:(MSErrorReport *)errorReport { - [NSNotificationCenter.defaultCenter postNotificationName:kShouldProcessErrorReportEvent - object:nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kShouldProcessErrorReportEvent object:nil]; NSLog(@"Should process error report with: %@", errorReport.exceptionReason); return YES; } - (void)crashes:(MSCrashes *)crashes willSendErrorReport:(MSErrorReport *)errorReport { - [NSNotificationCenter.defaultCenter postNotificationName:kWillSendErrorReportEvent - object:nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kWillSendErrorReportEvent object:nil]; NSLog(@"Will send error report with: %@", errorReport.exceptionReason); } - (void)crashes:(MSCrashes *)crashes didSucceedSendingErrorReport:(MSErrorReport *)errorReport { - [NSNotificationCenter.defaultCenter postNotificationName:kDidSucceedSendingErrorReportEvent - object:nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kDidSucceedSendingErrorReportEvent object:nil]; NSLog(@"Did succeed error report sending with: %@", errorReport.exceptionReason); } - (void)crashes:(MSCrashes *)crashes didFailSendingErrorReport:(MSErrorReport *)errorReport withError:(NSError *)error { - [NSNotificationCenter.defaultCenter postNotificationName:kDidFailSendingErrorReportEvent - object:nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kDidFailSendingErrorReportEvent object:nil]; NSLog(@"Did fail sending report with: %@, and error: %@", errorReport.exceptionReason, error.localizedDescription); } @@ -226,23 +222,32 @@ - (BOOL)distribute:(MSDistribute *)distribute releaseAvailableWithDetails:(MSRel #pragma mark - MSPushDelegate - (void)push:(MSPush *)push didReceivePushNotification:(MSPushNotification *)pushNotification { + NSString *title = pushNotification.title; NSString *message = pushNotification.message; + NSMutableString *customData = nil; for (NSString *key in pushNotification.customData) { - message = [NSString stringWithFormat:@"%@\n%@: %@", message, key, [pushNotification.customData objectForKey:key]]; + ([customData length] == 0) ? customData = [NSMutableString new] : [customData appendString:@", "]; + [customData appendFormat:@"%@: %@", key, [pushNotification.customData objectForKey:key]]; + } + if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) { + NSLog(@"%@ Notification received in background, title: \"%@\", message: \"%@\", custom data: \"%@\"", kPUPLogTag, + title, message, customData); + } else { + message = [NSString stringWithFormat:@"%@%@%@", (message ? message : @""), (message && customData ? @"\n" : @""), + (customData ? customData : @"")]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title + message:message + delegate:self + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; } - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:pushNotification.title - message:message - delegate:self - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; } #pragma mark - MSAnalyticsDelegate - (void)analytics:(MSAnalytics *)analytics willSendEventLog:(MSEventLog *)eventLog { - [NSNotificationCenter.defaultCenter postNotificationName:kWillSendEventLog - object:[self msLogEventToLocal:eventLog]]; + [NSNotificationCenter.defaultCenter postNotificationName:kWillSendEventLog object:[self msLogEventToLocal:eventLog]]; } - (void)analytics:(MSAnalytics *)analytics didSucceedSendingEventLog:(MSEventLog *)eventLog { @@ -255,14 +260,14 @@ - (void)analytics:(MSAnalytics *)analytics didFailSendingEventLog:(MSEventLog *) object:[self msLogEventToLocal:eventLog]]; } -- (EventLog*) msLogEventToLocal:(MSEventLog*) msLog { +- (EventLog *)msLogEventToLocal:(MSEventLog *)msLog { EventLog *log = [EventLog new]; log.eventName = msLog.name; if (!msLog.properties) { return log; } - //Collect props + // Collect props for (NSString *key in msLog.properties) { NSString *value = [msLog.properties objectForKey:key]; [log.properties setObject:value forKey:key]; @@ -272,7 +277,7 @@ - (EventLog*) msLogEventToLocal:(MSEventLog*) msLog { #pragma mark - Public -+(UIViewController*)crashResultViewController { ++ (UIViewController *)crashResultViewController { return crashResultViewController; } diff --git a/Puppet/Puppet/Info.plist b/Puppet/Puppet/Info.plist index b056c0a0cf..90d89b54f9 100644 --- a/Puppet/Puppet/Info.plist +++ b/Puppet/Puppet/Info.plist @@ -18,17 +18,36 @@ 1.0 CFBundleSignature ???? + CFBundleURLTypes + + + CFBundleTypeRole + None + CFBundleURLName + com.microsoft.azure.mobile.puppet + CFBundleURLSchemes + + mobilecenter-7dfb022a-17b5-4d4a-9c75-12bc3ef5e6b7 + + + CFBundleVersion 1 LSApplicationCategoryType LSRequiresIPhoneOS + MSAppName + puppet-ios NSAppTransportSecurity NSAllowsArbitraryLoads + UIBackgroundModes + + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -43,20 +62,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CFBundleURLTypes - - - CFBundleTypeRole - None - CFBundleURLName - com.microsoft.azure.mobile.puppet - CFBundleURLSchemes - - mobilecenter-7dfb022a-17b5-4d4a-9c75-12bc3ef5e6b7 - - - - MSAppName - puppet-ios diff --git a/Sasquatch/Sasquatch.xcodeproj/project.pbxproj b/Sasquatch/Sasquatch.xcodeproj/project.pbxproj index ee5c3bed40..132fc984e1 100644 --- a/Sasquatch/Sasquatch.xcodeproj/project.pbxproj +++ b/Sasquatch/Sasquatch.xcodeproj/project.pbxproj @@ -722,6 +722,9 @@ DevelopmentTeam = L4RARDNZ2Y; ProvisioningStyle = Manual; SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 1; + }; com.apple.Push = { enabled = 1; }; @@ -732,6 +735,9 @@ DevelopmentTeam = L4RARDNZ2Y; ProvisioningStyle = Manual; SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 1; + }; com.apple.Push = { enabled = 1; }; diff --git a/Sasquatch/SasquatchObjC/AppDelegate.m b/Sasquatch/SasquatchObjC/AppDelegate.m index 6fc5cb903e..b33f0d7fc8 100644 --- a/Sasquatch/SasquatchObjC/AppDelegate.m +++ b/Sasquatch/SasquatchObjC/AppDelegate.m @@ -130,9 +130,9 @@ - (void)crashes:(MSCrashes *)crashes didFailSendingErrorReport:(MSErrorReport *) forErrorReport:(MSErrorReport *)errorReport { MSErrorAttachmentLog *attachment1 = [MSErrorAttachmentLog attachmentWithText:@"Hello world!" filename:@"hello.txt"]; MSErrorAttachmentLog *attachment2 = - [MSErrorAttachmentLog attachmentWithBinary:[@"Fake image" dataUsingEncoding:NSUTF8StringEncoding] - filename:@"fake_image.jpeg" - contentType:@"image/jpeg"]; + [MSErrorAttachmentLog attachmentWithBinary:[@"Fake image" dataUsingEncoding:NSUTF8StringEncoding] + filename:@"fake_image.jpeg" + contentType:@"image/jpeg"]; return @[ attachment1, attachment2 ]; } @@ -165,16 +165,26 @@ - (BOOL)distribute:(MSDistribute *)distribute releaseAvailableWithDetails:(MSRel #pragma mark - MSPushDelegate - (void)push:(MSPush *)push didReceivePushNotification:(MSPushNotification *)pushNotification { + NSString *title = pushNotification.title; NSString *message = pushNotification.message; + NSMutableString *customData = nil; for (NSString *key in pushNotification.customData) { - message = [NSString stringWithFormat:@"%@\n%@: %@", message, key, [pushNotification.customData objectForKey:key]]; + ([customData length] == 0) ? customData = [NSMutableString new] : [customData appendString:@", "]; + [customData appendFormat:@"%@: %@", key, [pushNotification.customData objectForKey:key]]; + } + if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) { + NSLog(@"Notification received in background, title: \"%@\", message: \"%@\", custom data: \"%@\"", title, message, + customData); + } else { + message = [NSString stringWithFormat:@"%@%@%@", (message ? message : @""), (message && customData ? @"\n" : @""), + (customData ? customData : @"")]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title + message:message + delegate:self + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; } - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:pushNotification.title - message:message - delegate:self - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; } @end diff --git a/Sasquatch/SasquatchObjC/Info.plist b/Sasquatch/SasquatchObjC/Info.plist index 41c45de6be..4947607958 100644 --- a/Sasquatch/SasquatchObjC/Info.plist +++ b/Sasquatch/SasquatchObjC/Info.plist @@ -33,6 +33,10 @@ 1 LSRequiresIPhoneOS + UIBackgroundModes + + remote-notification + UILaunchStoryboardName Sasquatch UIMainStoryboardFile @@ -54,18 +58,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CFBundleURLTypes - - - CFBundleTypeRole - None - CFBundleURLName - com.microsoft.azure.mobile.sasquatchobjc - CFBundleURLSchemes - - mobilecenter-3ccfe7f5-ec01-4de5-883c-f563bbbe147a - - - diff --git a/Sasquatch/SasquatchSwift/AppDelegate.swift b/Sasquatch/SasquatchSwift/AppDelegate.swift index 2f8527c507..26653dc550 100644 --- a/Sasquatch/SasquatchSwift/AppDelegate.swift +++ b/Sasquatch/SasquatchSwift/AppDelegate.swift @@ -97,7 +97,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, MSCrashesDelegate, MSDist } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - MSPush.didReceiveRemoteNotification(userInfo) + let result: Bool = MSPush.didReceiveRemoteNotification(userInfo) + if result { + completionHandler(.newData) + } + else { + completionHandler(.noData) + } } func applicationWillResignActive(_ application: UIApplication) { @@ -157,12 +163,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, MSCrashesDelegate, MSDist // Push Delegate func push(_ push: MSPush!, didReceive pushNotification: MSPushNotification!) { - var message: String = pushNotification.message + let title: String? = pushNotification.title + var message: String = pushNotification.message ?? "" + var customData: String = "" for item in pushNotification.customData { - message = String(format: "%@\n%@: %@", message, item.key, item.value) + customData = ((customData.isEmpty) ? "" : "\(customData), ") + "\(item.key): \(item.value)" + } + if (UIApplication.shared.applicationState == .background) { + NSLog("Notification received in background, title: \"\(title ?? "")\", message: \"\(message)\", custom data: \"\(customData)\""); + } else { + message = message + ((customData.isEmpty) ? "" : "\n\(customData)") + let alert = UIAlertView(title: title, message: message, delegate: self, cancelButtonTitle: "OK") + alert.show() } - let alert = UIAlertView(title: pushNotification.title, message: message, delegate: self, cancelButtonTitle: "OK") - alert.show() } } diff --git a/Sasquatch/SasquatchSwift/Info.plist b/Sasquatch/SasquatchSwift/Info.plist index 49048431f3..d21e782670 100644 --- a/Sasquatch/SasquatchSwift/Info.plist +++ b/Sasquatch/SasquatchSwift/Info.plist @@ -33,6 +33,12 @@ 1 LSRequiresIPhoneOS + MobileCenterAppDelegateForwarderEnabled + + UIBackgroundModes + + remote-notification + UILaunchStoryboardName Sasquatch UIMainStoryboardFile @@ -54,7 +60,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - MobileCenterAppDelegateForwarderEnabled - From 501eded88bc1e01a8da89954aa15febfcc68c3d3 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Mon, 18 Sep 2017 15:05:51 -0700 Subject: [PATCH 47/55] Uncomment checkForUpdatesAllowed --- .../MobileCenterDistribute/MSDistribute.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index a9f4efe030..87de6189d2 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -599,13 +599,12 @@ - (BOOL)handleUpdate:(MSReleaseDetails *)details { } - (BOOL)checkForUpdatesAllowed { - return YES; // // Check if we are not in AppStore or TestFlight environments. - // BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; - // - // // Check if a debugger is attached. - // BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; - // return environmentOkay && noDebuggerAttached; + BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; + + // Check if a debugger is attached. + BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; + return environmentOkay && noDebuggerAttached; } - (BOOL)isNewerVersion:(MSReleaseDetails *)details { From 7eace22544d7e09c23a310f401828e83d1d85515 Mon Sep 17 00:00:00 2001 From: Murat Baysangurov Date: Thu, 14 Sep 2017 15:33:57 +0300 Subject: [PATCH 48/55] Fixes MSDistributeTests compilation --- .../MobileCenterDistributeTests/MSDistributeTests.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m index bc133ab65a..da58299906 100644 --- a/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m +++ b/MobileCenterDistribute/MobileCenterDistributeTests/MSDistributeTests.m @@ -25,7 +25,7 @@ static NSString *const kMSDistributeServiceName = @"Distribute"; // Mocked SFSafariViewController for url validation. -@interface SFSafariViewController : UIViewController +@interface SFSafariViewControllerMock : UIViewController @property(class, nonatomic) NSURL *url; @@ -35,7 +35,7 @@ - (instancetype)initWithURL:(NSURL *)url; static NSURL *sfURL; -@implementation SFSafariViewController +@implementation SFSafariViewControllerMock - (instancetype)initWithURL:(NSURL *)url { if ((self = [self init])) { @@ -229,7 +229,7 @@ - (void)testOpenURLInSafariViewControllerWithUrl { // When @try { - [self.sut openURLInSafariViewControllerWith:url fromClass:[SFSafariViewController class]]; + [self.sut openURLInSafariViewControllerWith:url fromClass:[SFSafariViewControllerMock class]]; } @catch (__attribute__((unused)) NSException *ex) { /** @@ -239,7 +239,7 @@ - (void)testOpenURLInSafariViewControllerWithUrl { } // Then - assertThat(SFSafariViewController.url, is(url)); + assertThat(SFSafariViewControllerMock.url, is(url)); } - (void)testSetApiUrlWorks { From 4808fd9d20c4dcd0cad672bcb99141d4279064f9 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Mon, 18 Sep 2017 19:58:24 -0700 Subject: [PATCH 49/55] Fix bad merge --- Puppet/Puppet.xcodeproj/project.pbxproj | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/Puppet/Puppet.xcodeproj/project.pbxproj b/Puppet/Puppet.xcodeproj/project.pbxproj index 0cba9c1679..a2bff0d190 100644 --- a/Puppet/Puppet.xcodeproj/project.pbxproj +++ b/Puppet/Puppet.xcodeproj/project.pbxproj @@ -262,27 +262,6 @@ remoteGlobalIDString = E82E1B5E1D1CA58D00D281C1; remoteInfo = Puppet; }; - 80493AC31F6A701A00E6E895 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E82E1B821D1CA63000D281C1 /* MobileCenter.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 0446DF2B1F3B864600C8E338; - remoteInfo = MobileCenterTVOSTests; - }; - 80493AD01F6A701A00E6E895 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E85547FB1D2D6C8D002DF6E2 /* MobileCenterAnalytics.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 0446DF541F3B8E6300C8E338; - remoteInfo = MobileCenterAnalyticsTVOSTests; - }; - 80493ADD1F6A701A00E6E895 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E82E1B7C1D1CA62900D281C1 /* MobileCenterCrashes.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 0446DF9D1F3B977100C8E338; - remoteInfo = MobileCenterCrashesTVOSTests; - }; B2C070CA1E5F59A90076D6A9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0471B91E1E4550670022F951 /* MobileCenterDistribute.xcodeproj */; From 5842f00a9410d23aaba04278158114f5f472e181 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 19 Sep 2017 11:44:06 -0700 Subject: [PATCH 50/55] Fix code signing issue on Sasquatch Mac --- SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj index 465a49d30e..93764de60a 100644 --- a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj +++ b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj @@ -440,8 +440,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer: Piyush Joshi (YG3U94CNDA)"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -493,8 +492,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer: Piyush Joshi (YG3U94CNDA)"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; @@ -522,7 +520,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -542,7 +539,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacObjC/SasquatchMacObjC.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -562,7 +558,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; @@ -581,7 +576,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = SasquatchMacSwift/SasquatchMacSwift.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = L4RARDNZ2Y; HEADER_SEARCH_PATHS = "$(SRCROOT)/../CrashLib/CrashLib"; From baaef6dbf804c5f9c6c1d34703a8ecaabc34f326 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 19 Sep 2017 13:23:31 -0700 Subject: [PATCH 51/55] Address comments --- .../MobileCenterDistribute/MSDistribute.m | 16 ++++++++-------- .../MobileCenterDistribute/MSDistributePrivate.h | 5 ----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m index 87de6189d2..e5c466173a 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistribute.m @@ -118,7 +118,6 @@ - (void)notifyUpdateAction:(MSUpdateAction)action { MSLogDebug([MSDistribute logTag], @"The release has already been processed."); return; } - switch (action) { case MSUpdateActionUpdate: #if TARGET_OS_SIMULATOR @@ -243,7 +242,7 @@ - (void)requestInstallInformationWith:(NSString *)releaseHash { }); #endif } else { - + // iOS 8.x. [self openURLInSafariApp:url]; } @@ -599,12 +598,13 @@ - (BOOL)handleUpdate:(MSReleaseDetails *)details { } - (BOOL)checkForUpdatesAllowed { - // // Check if we are not in AppStore or TestFlight environments. - BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; - - // Check if a debugger is attached. - BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; - return environmentOkay && noDebuggerAttached; + + // Check if we are not in AppStore or TestFlight environments. + BOOL environmentOkay = [MSUtility currentAppEnvironment] == MSEnvironmentOther; + + // Check if a debugger is attached. + BOOL noDebuggerAttached = ![MSMobileCenter isDebuggerAttached]; + return environmentOkay && noDebuggerAttached; } - (BOOL)isNewerVersion:(MSReleaseDetails *)details { diff --git a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h index 33e1fd22fa..1634414eb8 100644 --- a/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h +++ b/MobileCenterDistribute/MobileCenterDistribute/MSDistributePrivate.h @@ -10,12 +10,7 @@ #import "MSAlertController.h" #import "MSUIAppDelegate.h" #import "MSDistribute.h" -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpartial-availability" #import -#pragma clang diagnostic pop -#endif NS_ASSUME_NONNULL_BEGIN From 4fbf418f16ef8a7faac0f21293e5e90a54c97c7e Mon Sep 17 00:00:00 2001 From: Clement Polet Date: Tue, 19 Sep 2017 13:42:01 -0700 Subject: [PATCH 52/55] Update mac apps prov profile --- SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj index 93764de60a..66683fa362 100644 --- a/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj +++ b/SasquatchMac/SasquatchMac.xcodeproj/project.pbxproj @@ -527,7 +527,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azure.mobile.sasquatchobjc.mac; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "018a0743-859a-4900-b422-d9f2ac50b32d"; + PROVISIONING_PROFILE = "53c1192d-4b44-4736-adaa-26ae32a577fb"; PROVISIONING_PROFILE_SPECIFIER = "MobileCenter Sasquatch Mac ObjC App"; SWIFT_OBJC_BRIDGING_HEADER = "SasquatchMac/SasquatchMac-Bridging-Header.h"; SWIFT_VERSION = 3.0; @@ -565,7 +565,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azure.mobile.sasquatchswift.mac; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "0699067d-8e83-4f2c-8983-a23d6e125080"; + PROVISIONING_PROFILE = "9a41723a-23e1-4bb8-a894-27af3871eb60"; PROVISIONING_PROFILE_SPECIFIER = "MobileCenter Sasquatch Mac Swift App"; SWIFT_VERSION = 3.0; }; @@ -583,7 +583,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azure.mobile.sasquatchswift.mac; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "0699067d-8e83-4f2c-8983-a23d6e125080"; + PROVISIONING_PROFILE = "9a41723a-23e1-4bb8-a894-27af3871eb60"; PROVISIONING_PROFILE_SPECIFIER = "MobileCenter Sasquatch Mac Swift App"; SWIFT_VERSION = 3.0; }; From 49964d9f4516c99142e7edb10e8456b305e7df34 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 19 Sep 2017 13:51:40 -0700 Subject: [PATCH 53/55] Remove IPHONEOS_DEPLOYMENT_TARGET from MobileCenter Project. --- MobileCenter/MobileCenter.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj index ead78aecb9..14d9c589b5 100644 --- a/MobileCenter/MobileCenter.xcodeproj/project.pbxproj +++ b/MobileCenter/MobileCenter.xcodeproj/project.pbxproj @@ -2058,7 +2058,6 @@ "DEBUG=1", "$(inherited)", ); - IPHONEOS_DEPLOYMENT_TARGET = 8.0; }; name = Debug; }; @@ -2066,7 +2065,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 0469D1B11F4DF89A00A43A8E /* MobileCenter Release.xcconfig */; buildSettings = { - IPHONEOS_DEPLOYMENT_TARGET = 8.0; }; name = Release; }; From 306311afe179baccee17ea4a188ab678d1936832 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 20 Sep 2017 13:18:16 -0700 Subject: [PATCH 54/55] Release 0.12.2 --- CHANGELOG.md | 14 ++++++++++++++ MobileCenter.podspec | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c5a2b7f0..d02c1fd57e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Mobile Center SDK for iOS Change Log +## Version 0.12.2 + +This version contains improvements. **Verified all functionalities against iOS 11 GM.** + +### MobileCenterCrashes + +* **[Improvement]** Added a millisecond precision to crash logs for more accurate log time. + +### MobileCenterDistribute + +* **[Improvement]** Improved swizzling behavior for deprecated `openURL` method if it is used by applications. + +___ + ## Version 0.12.1 This version contains bug fixes. diff --git a/MobileCenter.podspec b/MobileCenter.podspec index 7a988d0b08..81cb199b21 100644 --- a/MobileCenter.podspec +++ b/MobileCenter.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'MobileCenter' - s.version = '0.12.1' + s.version = '0.12.2' s.summary = 'Mobile Center is mission control for mobile apps. Get faster release cycles, higher-quality apps, and the insights to build what users want.' s.description = <<-DESC From 24d5cbebc6589b0020442babfa0bb4a16a293e7a Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 20 Sep 2017 14:04:28 -0700 Subject: [PATCH 55/55] Add a fix to change log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d02c1fd57e..5dd81362d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Version 0.12.2 -This version contains improvements. **Verified all functionalities against iOS 11 GM.** +This version contains a buf fix and improvements. **Verified all functionalities against iOS 11 GM.** ### MobileCenterCrashes @@ -11,6 +11,7 @@ This version contains improvements. **Verified all functionalities against iOS 1 ### MobileCenterDistribute * **[Improvement]** Improved swizzling behavior for deprecated `openURL` method if it is used by applications. +* **[Fix]** Fixed being stuck on activating in-app update. It is back to open Safari in-app page for activation. ___