From 1b14f9a10666aec5693adb07a91aa35ad03490ce Mon Sep 17 00:00:00 2001 From: Robin Macharg Date: Fri, 24 Jan 2020 15:21:00 +0000 Subject: [PATCH 1/2] refactor: rename BugsnagCrashReport to BugsnagEvent --- iOS/Bugsnag.xcodeproj/project.pbxproj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/iOS/Bugsnag.xcodeproj/project.pbxproj b/iOS/Bugsnag.xcodeproj/project.pbxproj index 65bfbd65b..31b74817c 100644 --- a/iOS/Bugsnag.xcodeproj/project.pbxproj +++ b/iOS/Bugsnag.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 8A2C8F581C6BBE3C00846019 /* BugsnagEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */; }; 8A2C8F5B1C6BBE3C00846019 /* BugsnagMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A2C8F5C1C6BBE3C00846019 /* BugsnagMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */; }; + 8A2C8F5B1C6BBE3C00846019 /* BugsnagMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8A2C8F5C1C6BBE3C00846019 /* BugsnagMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */; }; 8A2C8F5E1C6BBE3C00846019 /* BugsnagNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */; }; 8A2C8F5F1C6BBE3C00846019 /* BugsnagSink.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */; }; 8A2C8F601C6BBE3C00846019 /* BugsnagSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4E1C6BBE3C00846019 /* BugsnagSink.m */; }; @@ -182,6 +184,7 @@ E7397E2C1F83BC2A0034242A /* BugsnagConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F441C6BBE3C00846019 /* BugsnagConfiguration.m */; }; E7397E2D1F83BC2A0034242A /* BugsnagEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */; }; E7397E2E1F83BC2A0034242A /* BugsnagMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */; }; + E7397E2E1F83BC2A0034242A /* BugsnagMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */; }; E7397E2F1F83BC2A0034242A /* BugsnagNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */; }; E7397E301F83BC2A0034242A /* BugsnagSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4E1C6BBE3C00846019 /* BugsnagSink.m */; }; E7397E311F83BC2A0034242A /* BugsnagHandledState.m in Sources */ = {isa = PBXBuildFile; fileRef = E737DEA11F73AD7400BC7C80 /* BugsnagHandledState.m */; }; @@ -260,6 +263,7 @@ E7397EEA1F83CFC20034242A /* BugsnagConfiguration.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F431C6BBE3C00846019 /* BugsnagConfiguration.h */; }; E7397EEB1F83CFC20034242A /* BugsnagEvent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F451C6BBE3C00846019 /* BugsnagEvent.h */; }; E7397EEC1F83CFC20034242A /* BugsnagMetadata.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */; }; + E7397EEC1F83CFC20034242A /* BugsnagMetaData.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */; }; E7397EED1F83CFC20034242A /* BugsnagNotifier.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F4B1C6BBE3C00846019 /* BugsnagNotifier.h */; }; E7397EEE1F83CFC20034242A /* BugsnagSink.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */; }; E7397EEF1F83CFC20034242A /* BugsnagHandledState.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E737DEA01F73AD7400BC7C80 /* BugsnagHandledState.h */; }; @@ -395,6 +399,7 @@ E7397EEA1F83CFC20034242A /* BugsnagConfiguration.h in CopyFiles */, E7397EEB1F83CFC20034242A /* BugsnagEvent.h in CopyFiles */, E7397EEC1F83CFC20034242A /* BugsnagMetadata.h in CopyFiles */, + E7397EEC1F83CFC20034242A /* BugsnagMetaData.h in CopyFiles */, E7397EED1F83CFC20034242A /* BugsnagNotifier.h in CopyFiles */, E7397EEE1F83CFC20034242A /* BugsnagSink.h in CopyFiles */, E7397EEF1F83CFC20034242A /* BugsnagHandledState.h in CopyFiles */, @@ -433,6 +438,8 @@ 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagEvent.m; path = ../Source/BugsnagEvent.m; sourceTree = SOURCE_ROOT; }; 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagMetadata.h; path = ../Source/BugsnagMetadata.h; sourceTree = SOURCE_ROOT; }; 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagMetadata.m; path = ../Source/BugsnagMetadata.m; sourceTree = SOURCE_ROOT; }; + 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagMetaData.h; path = ../Source/BugsnagMetaData.h; sourceTree = SOURCE_ROOT; }; + 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagMetaData.m; path = ../Source/BugsnagMetaData.m; sourceTree = SOURCE_ROOT; }; 8A2C8F4B1C6BBE3C00846019 /* BugsnagNotifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagNotifier.h; path = ../Source/BugsnagNotifier.h; sourceTree = SOURCE_ROOT; }; 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagNotifier.m; path = ../Source/BugsnagNotifier.m; sourceTree = SOURCE_ROOT; }; 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagSink.h; path = ../Source/BugsnagSink.h; sourceTree = SOURCE_ROOT; }; @@ -738,6 +745,7 @@ 4BE6C42522CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m */, 8A2C8F8C1C6BBFDD00846019 /* BugsnagEventTests.m */, 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */, + 4B47970922A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m */, 8A4E733E1DC13281001F7CC8 /* BugsnagConfigurationTests.m */, 8A2C8F8D1C6BBFDD00846019 /* BugsnagSinkTests.m */, E77316E11F73B46600A14F06 /* BugsnagHandledStateTest.m */, @@ -1319,6 +1327,7 @@ E7397E2C1F83BC2A0034242A /* BugsnagConfiguration.m in Sources */, E7397E2D1F83BC2A0034242A /* BugsnagEvent.m in Sources */, E7397E2E1F83BC2A0034242A /* BugsnagMetadata.m in Sources */, + E7397E2E1F83BC2A0034242A /* BugsnagMetaData.m in Sources */, E7397E2F1F83BC2A0034242A /* BugsnagNotifier.m in Sources */, E7397E301F83BC2A0034242A /* BugsnagSink.m in Sources */, E7397E311F83BC2A0034242A /* BugsnagHandledState.m in Sources */, From 0400c6e76416a47a3e378c6fde9f67a7fef0e6e7 Mon Sep 17 00:00:00 2001 From: Robin Macharg Date: Wed, 5 Feb 2020 17:10:51 +0000 Subject: [PATCH 2/2] feat: add per-BugsnagEvent mutable apiKey --- Bugsnag.podspec.json | 2 +- CHANGELOG.md | 5 + Source/BugsnagConfiguration.h | 1 + Source/BugsnagConfiguration.m | 30 +++-- Source/BugsnagEvent.h | 7 + Source/BugsnagEvent.m | 26 ++++ Tests/BugsnagEventTests.m | 182 +++++++++++++++++--------- Tests/BugsnagTestConstants.h | 2 + iOS/Bugsnag.xcodeproj/project.pbxproj | 14 +- 9 files changed, 180 insertions(+), 89 deletions(-) diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index 6c75c5b93..b8a4e534a 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -26,6 +26,6 @@ "requires_arc": true, "public_header_files": [ "Source/BSG_KSCrashReportWriter.h", - "Source/Bugsnag{,MetaData,Configuration,Breadcrumb,Event,Plugin}.h" + "Source/Bugsnag{,Metadata,Configuration,Breadcrumb,Event,Plugin}.h" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8136018bd..c2f1b6680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ Bugsnag Notifiers on other platforms. * Add a breadcrumb when Bugsnag first starts with the message "Bugsnag loaded" [#445](https://github.com/bugsnag/bugsnag-cocoa/pull/445) +* Add a per-Event `apiKey` property. This defaults to the global + `BugsnagConfiguration` value but can be overridden in event passed to the + `Bugsnag.notify()` callback. + [#458](https://github.com/bugsnag/bugsnag-cocoa/pull/458) + ## Bug fixes * Fix possible report corruption when using `notify()` from multiple threads diff --git a/Source/BugsnagConfiguration.h b/Source/BugsnagConfiguration.h index 683d80e2a..e7b3467f6 100644 --- a/Source/BugsnagConfiguration.h +++ b/Source/BugsnagConfiguration.h @@ -84,6 +84,7 @@ typedef NSDictionary *_Nullable (^BugsnagBeforeNotifyHook)( NSArray *_Nonnull rawEventReports, NSDictionary *_Nonnull report); @interface BugsnagConfiguration : NSObject + /** * The API key of a Bugsnag project */ diff --git a/Source/BugsnagConfiguration.m b/Source/BugsnagConfiguration.m index 64969b744..53a798825 100644 --- a/Source/BugsnagConfiguration.m +++ b/Source/BugsnagConfiguration.m @@ -57,6 +57,21 @@ @interface BugsnagConfiguration () @implementation BugsnagConfiguration +// MARK: - Class Methods + +/** + * Determine the apiKey-validity of a passed-in string: + * Exactly 32 hexadecimal digits. + */ ++ (BOOL)isValidApiKey:(NSString *)apiKey { + NSCharacterSet *chars = [[NSCharacterSet + characterSetWithCharactersInString:@"0123456789ABCDEF"] invertedSet]; + BOOL isHex = (NSNotFound == [[apiKey uppercaseString] rangeOfCharacterFromSet:chars].location); + return isHex && [apiKey length] == BSGApiKeyLength; +} + +// MARK: - Instance Methods + /** * Should not be called, but if it _is_ then fail meaningfully rather than silently */ @@ -70,7 +85,7 @@ - (instancetype)init { -(instancetype)initWithApiKey:(NSString *)apiKey error:(NSError * _Nullable __autoreleasing * _Nullable)error { - if (! [self isValidApiKey:apiKey]) { + if (! [BugsnagConfiguration isValidApiKey:apiKey]) { *error = [NSError errorWithDomain:BSGConfigurationErrorDomain code:BSGConfigurationErrorInvalidApiKey userInfo:nil]; @@ -279,7 +294,7 @@ - (NSString *)apiKey { } - (void)setApiKey:(NSString *)apiKey { - if ([self isValidApiKey:apiKey]) { + if ([BugsnagConfiguration isValidApiKey:apiKey]) { [self willChangeValueForKey:NSStringFromSelector(@selector(apiKey))]; _apiKey = apiKey; [self didChangeValueForKey:NSStringFromSelector(@selector(apiKey))]; @@ -319,17 +334,6 @@ - (BOOL)isValidUrl:(NSURL *)url { return url != nil && url.scheme != nil && url.host != nil; } -/** - * Determine the apiKey-validity of a passed-in string: - * Exactly 32 hexadecimal digits. - */ -- (BOOL)isValidApiKey:(NSString *)apiKey { - NSCharacterSet *chars = [[NSCharacterSet - characterSetWithCharactersInString:@"0123456789ABCDEF"] invertedSet]; - BOOL isHex = (NSNotFound == [[apiKey uppercaseString] rangeOfCharacterFromSet:chars].location); - return isHex && [apiKey length] == BSGApiKeyLength; -} - - (NSUInteger)maxBreadcrumbs { return self.breadcrumbs.capacity; } diff --git a/Source/BugsnagEvent.h b/Source/BugsnagEvent.h index 00ce400dc..0e5cdd879 100644 --- a/Source/BugsnagEvent.h +++ b/Source/BugsnagEvent.h @@ -177,6 +177,13 @@ __deprecated_msg("Use toJson: instead."); */ @property(readonly, nonnull) BugsnagHandledState *handledState; +/** + * A per-event override for the apiKey. + * - Reads default to the BugsnagConfiguration apiKey value unless explicitly set. + * - Writes are not persisted to BugsnagConfiguration. + */ +@property(readwrite, copy, nonnull) NSString *apiKey; + /** * Property overrides */ diff --git a/Source/BugsnagEvent.m b/Source/BugsnagEvent.m index 4b16a2df2..cb3777ca6 100644 --- a/Source/BugsnagEvent.m +++ b/Source/BugsnagEvent.m @@ -191,6 +191,10 @@ + (instancetype)errorDataFromThreads:(NSArray *)threads; - (instancetype)initWithClass:(NSString *_Nonnull)errorClass message:(NSString *_Nonnull)errorMessage NS_DESIGNATED_INITIALIZER; @end +@interface BugsnagConfiguration (BugsnagEvent) ++ (BOOL)isValidApiKey:(NSString *_Nullable)apiKey; +@end + @interface BugsnagEvent () /** @@ -368,6 +372,28 @@ - (void)addMetadata:(NSDictionary *_Nonnull)tabData self.metadata = allMetadata; } +@synthesize apiKey = _apiKey; + +- (NSString *)apiKey { + if (! _apiKey) { + _apiKey = Bugsnag.configuration.apiKey; + } + return _apiKey; +} + + +- (void)setApiKey:(NSString *)apiKey { + if ([BugsnagConfiguration isValidApiKey:apiKey]) { + _apiKey = apiKey; + } + + // A malformed apiKey should not cause an error: the fallback global value + // in BugsnagConfiguration will do to get the event reported. + else { + bsg_log_warn(@"Attempted to set an invalid Event API key."); + } +} + - (void)addAttribute:(NSString *)attributeName withValue:(id)value toTabWithName:(NSString *)tabName { diff --git a/Tests/BugsnagEventTests.m b/Tests/BugsnagEventTests.m index de9178844..8dc64441c 100644 --- a/Tests/BugsnagEventTests.m +++ b/Tests/BugsnagEventTests.m @@ -26,14 +26,14 @@ - (void)testNotifyReleaseStagesSendsFromConfig { config.releaseStage = @"foo"; BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; - BugsnagEvent *report = + BugsnagEvent *event = [[BugsnagEvent alloc] initWithErrorName:@"Bad error" errorMessage:@"it was so bad" configuration:config metadata:@{} handledState:state session:nil]; - XCTAssertTrue([report shouldBeSent]); + XCTAssertTrue([event shouldBeSent]); } - (void)testNotifyReleaseStagesSkipsSendFromConfig { @@ -43,14 +43,14 @@ - (void)testNotifyReleaseStagesSkipsSendFromConfig { BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; - BugsnagEvent *report = + BugsnagEvent *event = [[BugsnagEvent alloc] initWithErrorName:@"Bad error" errorMessage:@"it was so bad" configuration:config metadata:@{} handledState:state session:nil]; - XCTAssertFalse([report shouldBeSent]); + XCTAssertFalse([event shouldBeSent]); } - (void)testSessionJson { @@ -66,14 +66,14 @@ - (void)testSessionJson { bugsnagSession.handledCount = 2; bugsnagSession.unhandledCount = 1; - BugsnagEvent *report = + BugsnagEvent *event = [[BugsnagEvent alloc] initWithErrorName:@"Bad error" errorMessage:@"it was so bad" configuration:config metadata:@{} handledState:state session:bugsnagSession]; - NSDictionary *json = [report toJson]; + NSDictionary *json = [event toJson]; XCTAssertNotNil(json); NSDictionary *session = json[@"session"]; @@ -89,35 +89,35 @@ - (void)testSessionJson { } - (void)testDefaultErrorMessageNilForEmptyThreads { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"threads" : @[] }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"Exception", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageNilForEmptyNotableAddresses { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"threads" : @[ @{@"crashed" : @YES, @"notable_addresses" : @{}} ] }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"Exception", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageForFatalErrorWithoutAdditionalMessage { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -131,18 +131,18 @@ - (void)testEnhancedErrorMessageForFatalErrorWithoutAdditionalMessage { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"fatal error", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageForAssertionWithoutAdditionalMessage { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -156,13 +156,13 @@ - (void)testEnhancedErrorMessageForAssertionWithoutAdditionalMessage { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"assertion failed", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } @@ -171,7 +171,7 @@ - (void)testEnhancedErrorMessageForAssertionError { @"assertion failed", @"Assertion failed", @"fatal error", @"Fatal error" ]) { - BugsnagEvent *report = + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @@ -191,20 +191,20 @@ - (void)testEnhancedErrorMessageForAssertionError { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(assertionName, payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"Something went wrong", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } } - (void)testEnhancedErrorMessageIgnoresFilePaths { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -223,18 +223,18 @@ - (void)testEnhancedErrorMessageIgnoresFilePaths { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"fatal error", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageIgnoresNonStrings { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -253,18 +253,18 @@ - (void)testEnhancedErrorMessageIgnoresNonStrings { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"fatal error", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageConcatenatesMultipleMessages { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -288,19 +288,19 @@ - (void)testEnhancedErrorMessageConcatenatesMultipleMessages { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"Fatal error", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"A message from beyond | Wo0o0o", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEnhancedErrorMessageIgnoresUnknownAssertionTypes { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{ + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ @"crash" : @{ @"threads" : @[ @{ @"crashed" : @YES, @@ -319,49 +319,49 @@ - (void)testEnhancedErrorMessageIgnoresUnknownAssertionTypes { } ] } }]; - NSDictionary *payload = [report toJson]; + NSDictionary *payload = [event toJson]; XCTAssertEqualObjects(@"Exception", payload[@"exceptions"][0][@"errorClass"]); XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(report.errorClass, + XCTAssertEqualObjects(event.errorClass, payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(report.errorMessage, + XCTAssertEqualObjects(event.errorMessage, payload[@"exceptions"][0][@"message"]); } - (void)testEmptyReport { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{}]; - XCTAssertNil(report); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{}]; + XCTAssertNil(event); } - (void)testUnhandledReportDepth { // unhandled reports should calculate their own depth NSDictionary *dict = @{@"user.depth": @2}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertEqual(report.depth, 0); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertEqual(event.depth, 0); } - (void)testHandledReportDepth { // handled reports should use the serialised depth BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; NSDictionary *dict = @{@"user.depth": @2, @"user.handledState": [state toJson]}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertEqual(report.depth, 2); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertEqual(event.depth, 2); } - (void)testUnhandledReportSeverity { // unhandled reports should calculate their own severity NSDictionary *dict = @{@"user.state.crash.severity": @"info"}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertEqual(report.severity, BSGSeverityError); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertEqual(event.severity, BSGSeverityError); } - (void)testHandledReportSeverity { // handled reports should use the serialised depth BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; NSDictionary *dict = @{@"user.state.crash.severity": @"info", @"user.handledState": [state toJson]}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertEqual(report.severity, BSGSeverityWarning); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertEqual(event.severity, BSGSeverityWarning); } - (void)testHandledReportMetaData { @@ -370,10 +370,10 @@ - (void)testHandledReportMetaData { [metadata addAttribute:@"Foo" withValue:@"Bar" toTabWithName:@"Custom"]; NSDictionary *dict = @{@"user.handledState": [state toJson], @"user.metaData": [metadata toDictionary]}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertNotNil(report.metadata); - XCTAssertEqual(report.metadata.count, 1); - XCTAssertEqualObjects(report.metadata[@"Custom"][@"Foo"], @"Bar"); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertNotNil(event.metadata); + XCTAssertEqual(event.metadata.count, 1); + XCTAssertEqualObjects(event.metadata[@"Custom"][@"Foo"], @"Bar"); } - (void)testUnhandledReportMetaData { @@ -381,10 +381,10 @@ - (void)testUnhandledReportMetaData { [metadata addAttribute:@"Foo" withValue:@"Bar" toTabWithName:@"Custom"]; NSDictionary *dict = @{@"user.metaData": [metadata toDictionary]}; - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:dict]; - XCTAssertNotNil(report.metadata); - XCTAssertEqual(report.metadata.count, 1); - XCTAssertEqualObjects(report.metadata[@"Custom"][@"Foo"], @"Bar"); + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:dict]; + XCTAssertNotNil(event.metadata); + XCTAssertEqual(event.metadata.count, 1); + XCTAssertEqualObjects(event.metadata[@"Custom"][@"Foo"], @"Bar"); } - (void)testAppVersionOverride { @@ -403,13 +403,67 @@ - (void)testAppVersionOverride { } - (void)testReportAddAttr { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{@"user.metaData": @{@"user": @{@"id": @"user id"}}}]; - [report addAttribute:@"foo" withValue:@"bar" toTabWithName:@"user"]; + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{@"user.metaData": @{@"user": @{@"id": @"user id"}}}]; + [event addAttribute:@"foo" withValue:@"bar" toTabWithName:@"user"]; } - (void)testReportAddMetadata { - BugsnagEvent *report = [[BugsnagEvent alloc] initWithKSReport:@{@"user.metaData": @{@"user": @{@"id": @"user id"}}}]; - [report addMetadata:@{@"foo": @"bar"} toTabWithName:@"user"]; + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{@"user.metaData": @{@"user": @{@"id": @"user id"}}}]; + [event addMetadata:@{@"foo": @"bar"} toTabWithName:@"user"]; +} + + +/** + * Test that BugsnagEvent has an apiKey value and supports non-persistent + * per-event changes to apiKey. + */ +- (void)testApiKey { + NSError *error; + BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1 error:&error]; + [Bugsnag startBugsnagWithConfiguration:config]; + + NSException *ex = [[NSException alloc] initWithName:@"myName" reason:@"myReason1" userInfo:nil]; + + // Check that the event is passed the apiKey + [Bugsnag notify:ex block:^(BugsnagEvent * _Nonnull event) { + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + }]; + + // Check that we can change it + [Bugsnag notify:ex block:^(BugsnagEvent * _Nonnull event) { + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + event.apiKey = DUMMY_APIKEY_32CHAR_2; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_2); + XCTAssertEqual(Bugsnag.configuration.apiKey, DUMMY_APIKEY_32CHAR_1); + }]; + + // Check that the global configuration is unaffected + [Bugsnag notify:ex block:^(BugsnagEvent * _Nonnull event) { + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + event.apiKey = DUMMY_APIKEY_32CHAR_1; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + XCTAssertEqual(Bugsnag.configuration.apiKey, DUMMY_APIKEY_32CHAR_1); + event.apiKey = DUMMY_APIKEY_32CHAR_3; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_3); + }]; + + // Check that previous local and global values are not persisted erroneously + Bugsnag.configuration.apiKey = DUMMY_APIKEY_32CHAR_4; + [Bugsnag notify:ex block:^(BugsnagEvent * _Nonnull event) { + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_4); + event.apiKey = DUMMY_APIKEY_32CHAR_1; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + XCTAssertEqual(Bugsnag.configuration.apiKey, DUMMY_APIKEY_32CHAR_4); + event.apiKey = DUMMY_APIKEY_32CHAR_2; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_2); + }]; + + // Check that validation is performed and that invalid API keys can't be set + Bugsnag.configuration.apiKey = DUMMY_APIKEY_32CHAR_1; + [Bugsnag notify:ex block:^(BugsnagEvent * _Nonnull event) { + event.apiKey = DUMMY_APIKEY_16CHAR; + XCTAssertEqual(event.apiKey, DUMMY_APIKEY_32CHAR_1); + }]; } @end diff --git a/Tests/BugsnagTestConstants.h b/Tests/BugsnagTestConstants.h index 4b63cadb2..599cbda01 100644 --- a/Tests/BugsnagTestConstants.h +++ b/Tests/BugsnagTestConstants.h @@ -17,6 +17,8 @@ // One string to rule(r) them all: 12345678901234567890123456789012345678901234567890 static NSString * _Nonnull const DUMMY_APIKEY_32CHAR_1 = @"0192837465afbecd0192837465afbecd"; // the correct length static NSString * _Nonnull const DUMMY_APIKEY_32CHAR_2 = @"aabbccddeeff00112233445566778899"; +static NSString * _Nonnull const DUMMY_APIKEY_32CHAR_3 = @"99887766554433221100ffeeddccbbaa"; +static NSString * _Nonnull const DUMMY_APIKEY_32CHAR_4 = @"98765432109876543210abcdefabcdef"; static NSString * _Nonnull const DUMMY_APIKEY_16CHAR = @"0192837465afbecd"; // too short static NSString * _Nonnull const DUMMY_APIKEY_48CHAR = @"0192837465afbecd0192837465afbecd0192837465afbecd"; // too long diff --git a/iOS/Bugsnag.xcodeproj/project.pbxproj b/iOS/Bugsnag.xcodeproj/project.pbxproj index 31b74817c..94b567ae7 100644 --- a/iOS/Bugsnag.xcodeproj/project.pbxproj +++ b/iOS/Bugsnag.xcodeproj/project.pbxproj @@ -7,14 +7,13 @@ objects = { /* Begin PBXBuildFile section */ - 4B47970A22A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */; }; 000DF29423DB4B4900A883CE /* TestConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 000DF29323DB4B4900A883CE /* TestConstants.m */; }; 000E6E9E23D8690F009D8194 /* BugsnagSwiftConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 000E6E9D23D8690F009D8194 /* BugsnagSwiftConfigurationTests.swift */; }; 000E6EA323D8AC8C009D8194 /* UPGRADING.md in Resources */ = {isa = PBXBuildFile; fileRef = 000E6E9F23D8AC8C009D8194 /* UPGRADING.md */; }; 000E6EA423D8AC8C009D8194 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA023D8AC8C009D8194 /* README.md */; }; 000E6EA523D8AC8C009D8194 /* VERSION in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA123D8AC8C009D8194 /* VERSION */; }; 000E6EA623D8AC8C009D8194 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA223D8AC8C009D8194 /* CHANGELOG.md */; }; - 4B47970A22A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B47970922A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m */; }; + 4B47970A22A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */; }; 4B775FCF22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B775FCE22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */; }; 4BE6C42622CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6C42522CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m */; }; 8A2C8F231C6BBD2300846019 /* Bugsnag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A2C8F181C6BBD2300846019 /* Bugsnag.framework */; }; @@ -29,8 +28,6 @@ 8A2C8F581C6BBE3C00846019 /* BugsnagEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */; }; 8A2C8F5B1C6BBE3C00846019 /* BugsnagMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A2C8F5C1C6BBE3C00846019 /* BugsnagMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */; }; - 8A2C8F5B1C6BBE3C00846019 /* BugsnagMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8A2C8F5C1C6BBE3C00846019 /* BugsnagMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */; }; 8A2C8F5E1C6BBE3C00846019 /* BugsnagNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */; }; 8A2C8F5F1C6BBE3C00846019 /* BugsnagSink.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */; }; 8A2C8F601C6BBE3C00846019 /* BugsnagSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4E1C6BBE3C00846019 /* BugsnagSink.m */; }; @@ -184,7 +181,6 @@ E7397E2C1F83BC2A0034242A /* BugsnagConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F441C6BBE3C00846019 /* BugsnagConfiguration.m */; }; E7397E2D1F83BC2A0034242A /* BugsnagEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */; }; E7397E2E1F83BC2A0034242A /* BugsnagMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */; }; - E7397E2E1F83BC2A0034242A /* BugsnagMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */; }; E7397E2F1F83BC2A0034242A /* BugsnagNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */; }; E7397E301F83BC2A0034242A /* BugsnagSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8F4E1C6BBE3C00846019 /* BugsnagSink.m */; }; E7397E311F83BC2A0034242A /* BugsnagHandledState.m in Sources */ = {isa = PBXBuildFile; fileRef = E737DEA11F73AD7400BC7C80 /* BugsnagHandledState.m */; }; @@ -263,7 +259,6 @@ E7397EEA1F83CFC20034242A /* BugsnagConfiguration.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F431C6BBE3C00846019 /* BugsnagConfiguration.h */; }; E7397EEB1F83CFC20034242A /* BugsnagEvent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F451C6BBE3C00846019 /* BugsnagEvent.h */; }; E7397EEC1F83CFC20034242A /* BugsnagMetadata.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */; }; - E7397EEC1F83CFC20034242A /* BugsnagMetaData.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */; }; E7397EED1F83CFC20034242A /* BugsnagNotifier.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F4B1C6BBE3C00846019 /* BugsnagNotifier.h */; }; E7397EEE1F83CFC20034242A /* BugsnagSink.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */; }; E7397EEF1F83CFC20034242A /* BugsnagHandledState.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E737DEA01F73AD7400BC7C80 /* BugsnagHandledState.h */; }; @@ -399,7 +394,7 @@ E7397EEA1F83CFC20034242A /* BugsnagConfiguration.h in CopyFiles */, E7397EEB1F83CFC20034242A /* BugsnagEvent.h in CopyFiles */, E7397EEC1F83CFC20034242A /* BugsnagMetadata.h in CopyFiles */, - E7397EEC1F83CFC20034242A /* BugsnagMetaData.h in CopyFiles */, + E7397EEC1F83CFC20034242A /* BugsnagMetadata.h in CopyFiles */, E7397EED1F83CFC20034242A /* BugsnagNotifier.h in CopyFiles */, E7397EEE1F83CFC20034242A /* BugsnagSink.h in CopyFiles */, E7397EEF1F83CFC20034242A /* BugsnagHandledState.h in CopyFiles */, @@ -438,8 +433,6 @@ 8A2C8F461C6BBE3C00846019 /* BugsnagEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagEvent.m; path = ../Source/BugsnagEvent.m; sourceTree = SOURCE_ROOT; }; 8A2C8F491C6BBE3C00846019 /* BugsnagMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagMetadata.h; path = ../Source/BugsnagMetadata.h; sourceTree = SOURCE_ROOT; }; 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagMetadata.m; path = ../Source/BugsnagMetadata.m; sourceTree = SOURCE_ROOT; }; - 8A2C8F491C6BBE3C00846019 /* BugsnagMetaData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagMetaData.h; path = ../Source/BugsnagMetaData.h; sourceTree = SOURCE_ROOT; }; - 8A2C8F4A1C6BBE3C00846019 /* BugsnagMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagMetaData.m; path = ../Source/BugsnagMetaData.m; sourceTree = SOURCE_ROOT; }; 8A2C8F4B1C6BBE3C00846019 /* BugsnagNotifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagNotifier.h; path = ../Source/BugsnagNotifier.h; sourceTree = SOURCE_ROOT; }; 8A2C8F4C1C6BBE3C00846019 /* BugsnagNotifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagNotifier.m; path = ../Source/BugsnagNotifier.m; sourceTree = SOURCE_ROOT; }; 8A2C8F4D1C6BBE3C00846019 /* BugsnagSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagSink.h; path = ../Source/BugsnagSink.h; sourceTree = SOURCE_ROOT; }; @@ -745,7 +738,6 @@ 4BE6C42522CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m */, 8A2C8F8C1C6BBFDD00846019 /* BugsnagEventTests.m */, 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */, - 4B47970922A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m */, 8A4E733E1DC13281001F7CC8 /* BugsnagConfigurationTests.m */, 8A2C8F8D1C6BBFDD00846019 /* BugsnagSinkTests.m */, E77316E11F73B46600A14F06 /* BugsnagHandledStateTest.m */, @@ -1327,7 +1319,7 @@ E7397E2C1F83BC2A0034242A /* BugsnagConfiguration.m in Sources */, E7397E2D1F83BC2A0034242A /* BugsnagEvent.m in Sources */, E7397E2E1F83BC2A0034242A /* BugsnagMetadata.m in Sources */, - E7397E2E1F83BC2A0034242A /* BugsnagMetaData.m in Sources */, + E7397E2E1F83BC2A0034242A /* BugsnagMetadata.m in Sources */, E7397E2F1F83BC2A0034242A /* BugsnagNotifier.m in Sources */, E7397E301F83BC2A0034242A /* BugsnagSink.m in Sources */, E7397E311F83BC2A0034242A /* BugsnagHandledState.m in Sources */,