diff --git a/.jazzy.yaml b/.jazzy.yaml index d02993894..98a085e61 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -2,11 +2,11 @@ author_url: "https://www.bugsnag.com" author: "Bugsnag Inc" clean: false # avoid deleting docs/.git framework_root: "Bugsnag" -github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.23.0/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.23.1/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.23.0" +module_version: "6.23.1" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index 88de9d5ce..ee5527290 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.23.0", + "version": "6.23.1", "summary": "The Bugsnag crash reporting framework for Apple platforms.", "homepage": "https://bugsnag.com", "license": "MIT", @@ -9,7 +9,7 @@ }, "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.23.0" + "tag": "v6.23.1" }, "ios": { "frameworks": [ diff --git a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m index b210134c9..962af8772 100644 --- a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m +++ b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m @@ -8,16 +8,13 @@ #import "BSGNotificationBreadcrumbs.h" -#import "BugsnagBreadcrumbs.h" -#import "BugsnagConfiguration+Private.h" -#import "BSGKeys.h" -#import "BSGUtils.h" -#import "BSGDefines.h" #import "BSGAppKit.h" +#import "BSGDefines.h" +#import "BSGKeys.h" #import "BSGUIKit.h" - -#define BSG_HAVE_TABLE_VIEW (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV) -#define BSG_HAVE_TEXT_CONTROL (TARGET_OS_OSX || TARGET_OS_IOS ) +#import "BSGUtils.h" +#import "BugsnagBreadcrumbs.h" +#import "BugsnagConfiguration+Private.h" BSG_OBJC_DIRECT_MEMBERS @interface BSGNotificationBreadcrumbs () @@ -170,30 +167,30 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration } - (NSArray *)automaticBreadcrumbControlEvents { -#if !BSG_HAVE_TEXT_CONTROL - return nil; -#elif BSG_HAVE_APPKIT - return @[ - NSControlTextDidBeginEditingNotification, - NSControlTextDidEndEditingNotification - ]; -#else +#if TARGET_OS_IOS return @[ UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidEndEditingNotification, UITextViewTextDidBeginEditingNotification, UITextViewTextDidEndEditingNotification ]; +#elif TARGET_OS_OSX + return @[ + NSControlTextDidBeginEditingNotification, + NSControlTextDidEndEditingNotification + ]; +#else + return nil; #endif } - (NSArray *)automaticBreadcrumbTableItemEvents { -#if !BSG_HAVE_TABLE_VIEW - return @[]; -#elif BSG_HAVE_APPKIT - return @[ NSTableViewSelectionDidChangeNotification ]; +#if TARGET_OS_IOS || TARGET_OS_TV + return @[UITableViewSelectionDidChangeNotification]; +#elif TARGET_OS_OSX + return @[NSTableViewSelectionDidChangeNotification]; #else - return @[ UITableViewSelectionDidChangeNotification ]; + return @[]; #endif } @@ -321,8 +318,6 @@ - (BOOL)tryAddSceneNotification:(NSNotification *)notification { #endif - (BOOL)tryAddWindowNotification:(NSNotification *)notification { -#if BSG_HAVE_WINDOW - #if TARGET_OS_IOS || TARGET_OS_TV if ([notification.name hasPrefix:@"UIWindow"] && [notification.object isKindOfClass:UIWINDOW]) { UIWindow *window = notification.object; @@ -365,7 +360,6 @@ - (BOOL)tryAddWindowNotification:(NSNotification *)notification { } #endif -#endif return NO; } @@ -380,8 +374,6 @@ - (void)addBreadcrumbForNotification:(NSNotification *)notification { } - (void)addBreadcrumbForTableViewNotification:(__unused NSNotification *)notification { -#if BSG_HAVE_TABLE_VIEW - #if TARGET_OS_IOS || TARGET_OS_TV NSIndexPath *indexPath = ((UITableView *)notification.object).indexPathForSelectedRow; [self addBreadcrumbWithType:BSGBreadcrumbTypeNavigation forNotificationName:notification.name metadata: @@ -391,8 +383,6 @@ - (void)addBreadcrumbForTableViewNotification:(__unused NSNotification *)notific [self addBreadcrumbWithType:BSGBreadcrumbTypeNavigation forNotificationName:notification.name metadata: tableView ? @{@"selectedRow" : @(tableView.selectedRow), @"selectedColumn" : @(tableView.selectedColumn)} : nil]; #endif - -#endif } - (void)addBreadcrumbForMenuItemNotification:(__unused NSNotification *)notification { diff --git a/Bugsnag/BugsnagInternals.h b/Bugsnag/BugsnagInternals.h index 445481b74..bc7f48d2e 100644 --- a/Bugsnag/BugsnagInternals.h +++ b/Bugsnag/BugsnagInternals.h @@ -22,7 +22,8 @@ #import "BugsnagHandledState.h" #import "BugsnagNotifier.h" -typedef NSMutableArray BSGFeatureFlagStore; +@interface BSGFeatureFlagStore : NSObject +@end NS_ASSUME_NONNULL_BEGIN diff --git a/Bugsnag/BugsnagSessionTracker.m b/Bugsnag/BugsnagSessionTracker.m index 9162fb399..25579a70e 100644 --- a/Bugsnag/BugsnagSessionTracker.m +++ b/Bugsnag/BugsnagSessionTracker.m @@ -66,7 +66,7 @@ - (void)startWithNotificationCenter:(NSNotificationCenter *)notificationCenter i bsg_log_debug(@"Not starting session because app is not in the foreground"); } -#if BSG_HAVE_APPKIT +#if TARGET_OS_OSX [notificationCenter addObserver:self selector:@selector(handleAppForegroundEvent) name:NSApplicationWillBecomeActiveNotification @@ -81,7 +81,7 @@ - (void)startWithNotificationCenter:(NSNotificationCenter *)notificationCenter i selector:@selector(handleAppBackgroundEvent) name:NSApplicationDidResignActiveNotification object:nil]; -#elif BSG_HAVE_WATCHKIT +#elif TARGET_OS_WATCH [notificationCenter addObserver:self selector:@selector(handleAppForegroundEvent) name:WKApplicationWillEnterForegroundNotification diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index bca1c4ce3..d78931ad8 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -195,7 +195,7 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration { [_configuration setUser:[BSG_KSSystemInfo deviceAndAppHash] withEmail:_configuration.user.email andName:_configuration.user.name]; } - _featureFlagStore = [configuration.featureFlagStore mutableCopy]; + _featureFlagStore = [configuration.featureFlagStore copy]; _state = [[BugsnagMetadata alloc] initWithDictionary:@{ BSGKeyClient: @{ @@ -275,7 +275,7 @@ - (void)start { [center addObserver:self selector:@selector(applicationWillTerminate:) -#if BSG_HAVE_APPKIT +#if TARGET_OS_OSX name:NSApplicationWillTerminateNotification #else name:UIApplicationWillTerminateNotification @@ -762,7 +762,7 @@ - (void)notifyInternal:(BugsnagEvent *_Nonnull)event // App hang events will already contain feature flags if (!event.featureFlagStore.count) { @synchronized (self.featureFlagStore) { - event.featureFlagStore = [self.featureFlagStore mutableCopy]; + event.featureFlagStore = [self.featureFlagStore copy]; } } @@ -976,7 +976,7 @@ - (void)setObserver:(BSGClientObserver)observer { }; @synchronized (self.featureFlagStore) { - for (BugsnagFeatureFlag *flag in self.featureFlagStore) { + for (BugsnagFeatureFlag *flag in self.featureFlagStore.allFlags) { observer(BSGClientObserverAddFeatureFlag, flag); } } @@ -1040,7 +1040,7 @@ - (void)appHangDetectedAtDate:(NSDate *)date withThreads:(NSArray) #import diff --git a/Bugsnag/Helpers/BSGDefines.h b/Bugsnag/Helpers/BSGDefines.h index 2b37308a4..057304363 100644 --- a/Bugsnag/Helpers/BSGDefines.h +++ b/Bugsnag/Helpers/BSGDefines.h @@ -11,7 +11,6 @@ #include // Capabilities dependent upon system defines and files -#define BSG_HAVE_APPKIT __has_include() #define BSG_HAVE_BATTERY ( TARGET_OS_IOS || TARGET_OS_WATCH) #define BSG_HAVE_MACH_EXCEPTIONS (TARGET_OS_OSX || TARGET_OS_IOS ) #define BSG_HAVE_MACH_THREADS (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV ) @@ -22,8 +21,6 @@ #define BSG_HAVE_SIGALTSTACK (TARGET_OS_OSX || TARGET_OS_IOS ) #define BSG_HAVE_SYSCALL (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV ) #define BSG_HAVE_UIDEVICE __has_include() -#define BSG_HAVE_UIKIT __has_include() -#define BSG_HAVE_WATCHKIT __has_include() #define BSG_HAVE_WINDOW (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV ) // Capabilities dependent upon previously defined capabilities diff --git a/Bugsnag/Helpers/BSGFeatureFlagStore.h b/Bugsnag/Helpers/BSGFeatureFlagStore.h index 6e4f32114..fbaf3a650 100644 --- a/Bugsnag/Helpers/BSGFeatureFlagStore.h +++ b/Bugsnag/Helpers/BSGFeatureFlagStore.h @@ -7,6 +7,7 @@ // #import "BugsnagInternals.h" +#import "BSGDefines.h" NS_ASSUME_NONNULL_BEGIN @@ -20,4 +21,24 @@ NSArray * BSGFeatureFlagStoreToJSON(BSGFeatureFlagStore *store); BSGFeatureFlagStore * BSGFeatureFlagStoreFromJSON(id _Nullable json); + +BSG_OBJC_DIRECT_MEMBERS +@interface BSGFeatureFlagStore () + +@property(nonatomic,nonnull,readonly) NSArray * allFlags; + ++ (nonnull BSGFeatureFlagStore *) fromJSON:(nonnull id)json; + +- (NSUInteger) count; + +- (void) addFeatureFlag:(nonnull NSString *)name withVariant:(nullable NSString *)variant; + +- (void) addFeatureFlags:(nonnull NSArray *)featureFlags; + +- (void) clear:(nullable NSString *)name; + +- (nonnull NSArray *) toJSON; + +@end + NS_ASSUME_NONNULL_END diff --git a/Bugsnag/Helpers/BSGFeatureFlagStore.m b/Bugsnag/Helpers/BSGFeatureFlagStore.m index 176211241..fd2ecaa77 100644 --- a/Bugsnag/Helpers/BSGFeatureFlagStore.m +++ b/Bugsnag/Helpers/BSGFeatureFlagStore.m @@ -11,43 +11,50 @@ #import "BSGKeys.h" #import "BugsnagFeatureFlag.h" -static void internalAddFeatureFlag(BSGFeatureFlagStore *store, BugsnagFeatureFlag *flag) { - [store removeObject:flag]; - [store addObject:flag]; -} - void BSGFeatureFlagStoreAddFeatureFlag(BSGFeatureFlagStore *store, NSString *name, NSString *_Nullable variant) { - internalAddFeatureFlag(store, [BugsnagFeatureFlag flagWithName:name variant:variant]); + [store addFeatureFlag:name withVariant:variant]; } void BSGFeatureFlagStoreAddFeatureFlags(BSGFeatureFlagStore *store, NSArray *featureFlags) { - for (BugsnagFeatureFlag *featureFlag in featureFlags) { - internalAddFeatureFlag(store, featureFlag); - } + [store addFeatureFlags:featureFlags]; } void BSGFeatureFlagStoreClear(BSGFeatureFlagStore *store, NSString *_Nullable name) { - if (name) { - [store removeObject:[BugsnagFeatureFlag flagWithName:(NSString * _Nonnull)name]]; - } else { - [store removeAllObjects]; - } + [store clear:name]; } NSArray * BSGFeatureFlagStoreToJSON(BSGFeatureFlagStore *store) { - NSMutableArray *result = [NSMutableArray array]; - for (BugsnagFeatureFlag *flag in store) { - if (flag.variant) { - [result addObject:@{BSGKeyFeatureFlag: flag.name, BSGKeyVariant: (NSString * _Nonnull)flag.variant}]; - } else { - [result addObject:@{BSGKeyFeatureFlag: flag.name}]; - } - } - return result; + return [store toJSON]; } BSGFeatureFlagStore * BSGFeatureFlagStoreFromJSON(id json) { - BSGFeatureFlagStore *store = [NSMutableArray array]; + return [BSGFeatureFlagStore fromJSON:json]; +} + + +/** + * Stores feature flags as a dictionary containing the flag name as a key, with the + * value being the index into an array containing the complete feature flag. + * + * Removals leave holes in the array, which gets rebuilt on clear once there are too many holes. + * + * This gives the access speed of a dictionary while keeping ordering intact. + */ +BSG_OBJC_DIRECT_MEMBERS +@interface BSGFeatureFlagStore () + +@property(nonatomic, readwrite) NSMutableArray *flags; +@property(nonatomic, readwrite) NSMutableDictionary *indices; + +@end + +static const int REBUILD_AT_HOLE_COUNT = 1000; + +BSG_OBJC_DIRECT_MEMBERS +@implementation BSGFeatureFlagStore + ++ (nonnull BSGFeatureFlagStore *) fromJSON:(nonnull id)json { + BSGFeatureFlagStore *store = [BSGFeatureFlagStore new]; if ([json isKindOfClass:[NSArray class]]) { for (id item in json) { if ([item isKindOfClass:[NSDictionary class]]) { @@ -57,10 +64,119 @@ void BSGFeatureFlagStoreClear(BSGFeatureFlagStore *store, NSString *_Nullable na if (![variant isKindOfClass:[NSString class]]) { variant = nil; } - [store addObject:[BugsnagFeatureFlag flagWithName:featureFlag variant:variant]]; + [store addFeatureFlag:featureFlag withVariant:variant]; } } } } return store; } + +- (nonnull instancetype) init { + if ((self = [super init]) != nil) { + _flags = [NSMutableArray new]; + _indices = [NSMutableDictionary new]; + } + return self; +} + +static inline int getIndexFromDict(NSDictionary *dict, NSString *name) { + NSNumber *boxedIndex = dict[name]; + if (boxedIndex == nil) { + return -1; + } + return boxedIndex.intValue; +} + +- (NSUInteger) count { + return self.indices.count; +} + +- (nonnull NSArray *) allFlags { + NSMutableArray *flags = [NSMutableArray arrayWithCapacity:self.indices.count]; + for (BugsnagFeatureFlag *flag in self.flags) { + if ([flag isKindOfClass:[BugsnagFeatureFlag class]]) { + [flags addObject:flag]; + } + } + return flags; +} + +- (void)rebuildIfTooManyHoles { + int holeCount = (int)self.flags.count - (int)self.indices.count; + if (holeCount < REBUILD_AT_HOLE_COUNT) { + return; + } + + NSMutableArray *newFlags = [NSMutableArray arrayWithCapacity:self.indices.count]; + NSMutableDictionary *newIndices = [NSMutableDictionary new]; + for (BugsnagFeatureFlag *flag in self.flags) { + if ([flag isKindOfClass:[BugsnagFeatureFlag class]]) { + [newFlags addObject:flag]; + } + } + + for (NSUInteger i = 0; i < newFlags.count; i++) { + BugsnagFeatureFlag *flag = newFlags[i]; + newIndices[flag.name] = @(i); + } + self.flags = newFlags; + self.indices = newIndices; +} + +- (void) addFeatureFlag:(nonnull NSString *)name withVariant:(nullable NSString *)variant { + BugsnagFeatureFlag *flag = [BugsnagFeatureFlag flagWithName:name variant:variant]; + + int index = getIndexFromDict(self.indices, name); + if (index >= 0) { + self.flags[(unsigned)index] = flag; + } else { + index = (int)self.flags.count; + [self.flags addObject:flag]; + self.indices[name] = @(index); + } +} + +- (void) addFeatureFlags:(nonnull NSArray *)featureFlags { + for (BugsnagFeatureFlag *flag in featureFlags) { + [self addFeatureFlag:flag.name withVariant:flag.variant]; + } +} + +- (void) clear:(nullable NSString *)name { + if (name != nil) { + int index = getIndexFromDict(self.indices, name); + if (index >= 0) { + self.flags[(unsigned)index] = [NSNull null]; + [self.indices removeObjectForKey:(id)name]; + [self rebuildIfTooManyHoles]; + } + } else { + [self.indices removeAllObjects]; + [self.flags removeAllObjects]; + } +} + +- (nonnull NSArray *) toJSON { + NSMutableArray *result = [NSMutableArray array]; + + for (BugsnagFeatureFlag *flag in self.flags) { + if ([flag isKindOfClass:[BugsnagFeatureFlag class]]) { + if (flag.variant) { + [result addObject:@{BSGKeyFeatureFlag:flag.name, BSGKeyVariant:(NSString *_Nonnull)flag.variant}]; + } else { + [result addObject:@{BSGKeyFeatureFlag:flag.name}]; + } + } + } + return result; +} + +- (id)copyWithZone:(NSZone *)zone { + BSGFeatureFlagStore *store = [[BSGFeatureFlagStore allocWithZone:zone] init]; + store.flags = [self.flags mutableCopy]; + store.indices = [self.indices mutableCopy]; + return store; +} + +@end diff --git a/Bugsnag/Helpers/BSGUIKit.h b/Bugsnag/Helpers/BSGUIKit.h index b21e3bcf5..f67aab93d 100644 --- a/Bugsnag/Helpers/BSGUIKit.h +++ b/Bugsnag/Helpers/BSGUIKit.h @@ -6,8 +6,6 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import "BSGDefines.h" - #if __has_include() #import diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index c792fe42e..c1c5c72bf 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -26,12 +26,12 @@ #import "BSG_KSCrash.h" -#import "BSG_KSCrashC.h" -#import "BSG_KSCrashIdentifier.h" -#import "BSGDefines.h" #import "BSGAppKit.h" +#import "BSGDefines.h" #import "BSGUIKit.h" #import "BSGWatchKit.h" +#import "BSG_KSCrashC.h" +#import "BSG_KSCrashIdentifier.h" // ============================================================================ #pragma mark - Constants - @@ -71,7 +71,7 @@ - (BSG_KSCrashType)install:(BSG_KSCrashType)crashTypes directory:(NSString *)dir free(recrashReportPath); NSNotificationCenter *nCenter = [NSNotificationCenter defaultCenter]; -#if BSG_HAVE_APPKIT +#if TARGET_OS_OSX // MacOS "active" serves the same purpose as "foreground" in iOS [nCenter addObserver:self selector:@selector(applicationDidEnterBackground) @@ -81,7 +81,7 @@ - (BSG_KSCrashType)install:(BSG_KSCrashType)crashTypes directory:(NSString *)dir selector:@selector(applicationWillEnterForeground) name:NSApplicationDidBecomeActiveNotification object:nil]; -#elif BSG_HAVE_WATCHKIT +#elif TARGET_OS_WATCH [nCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:WKApplicationDidBecomeActiveNotification diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index 60969a36c..6ac4b92c1 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -760,7 +760,7 @@ - (void)setUnhandled:(BOOL)unhandled { // MARK: - - (NSArray *)featureFlags { - return [self.featureFlagStore copy]; + return self.featureFlagStore.allFlags; } - (void)addFeatureFlagWithName:(NSString *)name variant:(nullable NSString *)variant { diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index e301f5ed3..777f4c9a1 100644 --- a/Bugsnag/Payload/BugsnagNotifier.m +++ b/Bugsnag/Payload/BugsnagNotifier.m @@ -23,7 +23,7 @@ - (instancetype)init { #else _name = @"Bugsnag Objective-C"; #endif - _version = @"6.23.0"; + _version = @"6.23.1"; _url = @"https://github.com/bugsnag/bugsnag-cocoa"; _dependencies = @[]; } diff --git a/BugsnagNetworkRequestPlugin.podspec.json b/BugsnagNetworkRequestPlugin.podspec.json index 871666876..3a3380f7c 100644 --- a/BugsnagNetworkRequestPlugin.podspec.json +++ b/BugsnagNetworkRequestPlugin.podspec.json @@ -1,16 +1,16 @@ { "name": "BugsnagNetworkRequestPlugin", - "version": "6.23.0", + "version": "6.23.1", "summary": "Network request monitoring support for Bugsnag.", "homepage": "https://bugsnag.com", "license": "MIT", "authors": { "Bugsnag": "notifiers@bugsnag.com" }, - "readme": "https://raw.githubusercontent.com/bugsnag/bugsnag-cocoa/v6.23.0/BugsnagNetworkRequestPlugin/README.md", + "readme": "https://raw.githubusercontent.com/bugsnag/bugsnag-cocoa/v6.23.1/BugsnagNetworkRequestPlugin/README.md", "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.23.0" + "tag": "v6.23.1" }, "dependencies": { "Bugsnag": "~> 6.13" diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b12299a9..fb700da3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ Changelog ========= +## 6.23.1 (2022-09-21) + +### Bug fixes + +* Fix a crash on Mac Catalyst when user interacts with help menu. + [#1484](https://github.com/bugsnag/bugsnag-cocoa/issues/1484) + [#1485](https://github.com/bugsnag/bugsnag-cocoa/pull/1485) + +* Fix feature flag ordering and insertion performance. + [#1481](https://github.com/bugsnag/bugsnag-cocoa/pull/1481) + ## 6.23.0 (2022-09-14) ### Enhancements diff --git a/Framework/Info.plist b/Framework/Info.plist index 6dafe14fe..485b5ec43 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.23.0 + 6.23.1 CFBundleVersion 1 diff --git a/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m b/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m index 1c91646f0..8144687d6 100644 --- a/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m +++ b/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m @@ -44,12 +44,12 @@ - (void)test { XCTAssertEqualObjects(BSGFeatureFlagStoreToJSON(store), (@[ @{@"featureFlag": @"featureC", @"variant": @"checked"}, + @{@"featureFlag": @"featureA"}, @{@"featureFlag": @"featureB"}, - @{@"featureFlag": @"featureA"} ])); - XCTAssertEqualObjects(BSGFeatureFlagStoreFromJSON(BSGFeatureFlagStoreToJSON(store)), - store); + XCTAssertEqualObjects(BSGFeatureFlagStoreToJSON(BSGFeatureFlagStoreFromJSON(BSGFeatureFlagStoreToJSON(store))), + BSGFeatureFlagStoreToJSON(store)); BSGFeatureFlagStoreClear(store, @"featureB"); XCTAssertEqualObjects(BSGFeatureFlagStoreToJSON(store), @@ -62,4 +62,68 @@ - (void)test { XCTAssertEqualObjects(BSGFeatureFlagStoreToJSON(store), @[]); } +- (void)testAddRemoveMany { + // Tests that rebuildIfTooManyHoles works as expected + + BSGFeatureFlagStore *store = [[BSGFeatureFlagStore alloc] init]; + + BSGFeatureFlagStoreAddFeatureFlag(store, @"blah", @"testing"); + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 1000; i++) { + NSString *name = [NSString stringWithFormat:@"%d-%d", j, i]; + BSGFeatureFlagStoreAddFeatureFlag(store, name, nil); + if (i < 999) { + BSGFeatureFlagStoreClear(store, name); + } + } + } + + XCTAssertEqualObjects(BSGFeatureFlagStoreToJSON(store), + (@[ + @{@"featureFlag": @"blah", @"variant": @"testing"}, + @{@"featureFlag": @"0-999"}, + @{@"featureFlag": @"1-999"}, + @{@"featureFlag": @"2-999"}, + @{@"featureFlag": @"3-999"}, + @{@"featureFlag": @"4-999"}, + @{@"featureFlag": @"5-999"}, + @{@"featureFlag": @"6-999"}, + @{@"featureFlag": @"7-999"}, + @{@"featureFlag": @"8-999"}, + @{@"featureFlag": @"9-999"}, + ])); +} + +- (void)testAddFeatureFlagPerformance { + BSGFeatureFlagStore *store = [[BSGFeatureFlagStore alloc] init]; + + __auto_type block = ^{ + for (int i = 0; i < 1000; i++) { + NSString *name = [NSString stringWithFormat:@"%d", i]; + BSGFeatureFlagStoreAddFeatureFlag(store, name, nil); + } + }; + + block(); + + [self measureBlock:block]; +} + +- (void)testDictionaryPerformance { + // For comparision to show the best performance possible + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + + __auto_type block = ^{ + for (int i = 0; i < 1000; i++) { + NSString *name = [NSString stringWithFormat:@"%d", i]; + [dictionary setObject:[NSNull null] forKey:name]; + } + }; + + block(); + + [self measureBlock:block]; +} + @end diff --git a/Tests/BugsnagTests/BugsnagSessionTrackerTest.m b/Tests/BugsnagTests/BugsnagSessionTrackerTest.m index ee3fccebc..016464429 100644 --- a/Tests/BugsnagTests/BugsnagSessionTrackerTest.m +++ b/Tests/BugsnagTests/BugsnagSessionTrackerTest.m @@ -155,9 +155,9 @@ - (void)testHandleAppForegroundEvent { - (void)testStartInBackground { [self.sessionTracker startWithNotificationCenter:NSNotificationCenter.defaultCenter isInForeground:NO]; XCTAssertNil(self.sessionTracker.runningSession, @"There should be no running session after starting tracker in background"); -#if BSG_HAVE_WATCHKIT +#if TARGET_OS_WATCH [NSNotificationCenter.defaultCenter postNotificationName:WKApplicationDidBecomeActiveNotification object:nil]; -#elif BSG_HAVE_APPKIT +#elif TARGET_OS_OSX [NSNotificationCenter.defaultCenter postNotificationName:NSApplicationDidBecomeActiveNotification object:nil]; #else [NSNotificationCenter.defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification object:nil]; diff --git a/Tests/BugsnagTests/Info.plist b/Tests/BugsnagTests/Info.plist index 6324f79b4..d3d6d89e1 100644 --- a/Tests/BugsnagTests/Info.plist +++ b/Tests/BugsnagTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.23.0 + 6.23.1 CFBundleVersion 1 diff --git a/Tests/TestHost-iOS/Info.plist b/Tests/TestHost-iOS/Info.plist index 2ac4a14c3..9c68dcc21 100644 --- a/Tests/TestHost-iOS/Info.plist +++ b/Tests/TestHost-iOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.23.0 + 6.23.1 CFBundleVersion 1 LSRequiresIPhoneOS diff --git a/VERSION b/VERSION index 0b31cc63b..4f05c0a69 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.23.0 +6.23.1