From 84481f2cad0ed3a70ac9cba013fcfd8568d8ef5c Mon Sep 17 00:00:00 2001 From: Robin Macharg Date: Wed, 5 Feb 2020 10:57:38 +0000 Subject: [PATCH] refactor: rename Bugsnag.addAttribute to addMetadata, add tests --- CHANGELOG.md | 2 + Source/Bugsnag.h | 13 ++-- Source/Bugsnag.m | 14 ++-- Tests/BugsnagTests.m | 64 +++++++++++++++++++ UPGRADING.md | 11 ++++ iOS/Bugsnag.xcodeproj/project.pbxproj | 11 +++- .../Swift Tests/BugsnagSwiftTests.swift | 36 +++++++++++ 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 Tests/BugsnagTests.m create mode 100644 iOS/BugsnagTests/Swift Tests/BugsnagSwiftTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 8136018bd..a5390c787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ 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) + +* `Bugsnag.addAttribute:value:tab:` is now `Bugsnag.addMetadataToSection::key:value:` ## Bug fixes diff --git a/Source/Bugsnag.h b/Source/Bugsnag.h index b2688526f..59c04b59f 100644 --- a/Source/Bugsnag.h +++ b/Source/Bugsnag.h @@ -153,15 +153,16 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; * * See also [Bugsnag configuration].metaData; * - * @param attributeName The name of the data. + * @param key The name of the data. * - * @param value Its value. + * @param value Its value. * - * @param tabName The tab to show it on on the Bugsnag dashboard. + * @param section The tab to show it on on the Bugsnag dashboard. */ -+ (void)addAttribute:(NSString *_Nonnull)attributeName - withValue:(id _Nullable)value - toTabWithName:(NSString *_Nonnull)tabName; ++ (void)addMetadataToSection:(NSString *_Nonnull)section + key:(NSString *_Nonnull)key + value:(id _Nullable)value + NS_SWIFT_NAME(addMetadata(_:key:value:)); /** Remove custom data from Bugsnag reports. * diff --git a/Source/Bugsnag.m b/Source/Bugsnag.m index 8e504a519..03035edc6 100644 --- a/Source/Bugsnag.m +++ b/Source/Bugsnag.m @@ -182,13 +182,17 @@ + (void)internalClientNotify:(NSException *_Nonnull)exception } } -+ (void)addAttribute:(NSString *)attributeName - withValue:(id)value - toTabWithName:(NSString *)tabName { +/** + * Add custom data to send to Bugsnag with every exception. If value is nil, + * delete the current value for attributeName + */ ++ (void)addMetadataToSection:(NSString *_Nonnull)section + key:(NSString *_Nonnull)key + value:(id _Nullable)value { if ([self bugsnagStarted]) { - [self.notifier.configuration.metaData addAttribute:attributeName + [self.notifier.configuration.metaData addAttribute:key withValue:value - toTabWithName:tabName]; + toTabWithName:section]; } } diff --git a/Tests/BugsnagTests.m b/Tests/BugsnagTests.m new file mode 100644 index 000000000..54f3cce70 --- /dev/null +++ b/Tests/BugsnagTests.m @@ -0,0 +1,64 @@ +// +// BugsnagTests.m +// Tests +// +// Created by Robin Macharg on 04/02/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// +// Unit tests of global Bugsnag behaviour + +#import "Bugsnag.h" +#import "BugsnagTestConstants.h" +#import + +@interface BugsnagTests : XCTestCase + +@end + +@implementation BugsnagTests + +/** + * Test that global metadata is added correctly, applied to each event, and + * deleted appropriately. + */ +- (void)testBugsnagMetadataAddition { + + NSError *error; + BugsnagConfiguration *configuration = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1 error:&error]; + [Bugsnag startBugsnagWithConfiguration:configuration]; + [Bugsnag addMetadataToSection:@"mySection1" key:@"aKey1" value:@"aValue1"]; + + // We should see our added metadata in every request. Let's try a couple: + + NSException *exception1 = [[NSException alloc] initWithName:@"exception1" reason:@"reason1" userInfo:nil]; + NSException *exception2 = [[NSException alloc] initWithName:@"exception2" reason:@"reason2" userInfo:nil]; + + [Bugsnag notify:exception1 block:^(BugsnagEvent * _Nonnull report) { + XCTAssertEqual([[[report metaData] valueForKey:@"mySection1"] valueForKey:@"aKey1"], @"aValue1"); + XCTAssertEqual([report errorClass], @"exception1"); + XCTAssertEqual([report errorMessage], @"reason1"); + XCTAssertNil([[report metaData] valueForKey:@"mySection2"]); + + // Add some additional metadata once we're sure it's not already there + [Bugsnag addMetadataToSection:@"mySection2" key:@"aKey2" value:@"aValue2"]; + }]; + + [Bugsnag notify:exception2 block:^(BugsnagEvent * _Nonnull report) { + XCTAssertEqual([[[report metaData] valueForKey:@"mySection1"] valueForKey:@"aKey1"], @"aValue1"); + XCTAssertEqual([[[report metaData] valueForKey:@"mySection2"] valueForKey:@"aKey2"], @"aValue2"); + XCTAssertEqual([report errorClass], @"exception2"); + XCTAssertEqual([report errorMessage], @"reason2"); + }]; + + // Check nil value causes deletions + + [Bugsnag addMetadataToSection:@"mySection1" key:@"aKey1" value:nil]; + [Bugsnag addMetadataToSection:@"mySection2" key:@"aKey2" value:nil]; + + [Bugsnag notify:exception1 block:^(BugsnagEvent * _Nonnull report) { + XCTAssertNil([[[report metaData] valueForKey:@"mySection1"] valueForKey:@"aKey1"]); + XCTAssertNil([[[report metaData] valueForKey:@"mySection2"] valueForKey:@"aKey2"]); + }]; +} + +@end diff --git a/UPGRADING.md b/UPGRADING.md index 19251ac9d..7c0aa2f63 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -40,4 +40,15 @@ Swift: - Bugsnag.setBreadcrumbCapacity(40) let config = BugsnagConfiguration() + config.setMaxBreadcrumbs(40) + let config = try BugsnagConfiguration("VALID 32 CHARACTER API KEY") + +ObjC: + +- [Bugsnag addAttribute:WithValuetoTabWithName:] ++ [Bugsnag addMetadataToSection:key:value:] + +Swift: + +- Bugsnag.addAttribute(attributeName:withValue:toTabWithName:) ++ Bugsnag.addMetadata(_:key:value:) ``` diff --git a/iOS/Bugsnag.xcodeproj/project.pbxproj b/iOS/Bugsnag.xcodeproj/project.pbxproj index cc469247d..9c5a0fc62 100644 --- a/iOS/Bugsnag.xcodeproj/project.pbxproj +++ b/iOS/Bugsnag.xcodeproj/project.pbxproj @@ -7,14 +7,15 @@ 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 */; }; + 00D7ACAD23E9C63000FBE4A7 /* BugsnagTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00D7ACAC23E9C63000FBE4A7 /* BugsnagTests.m */; }; + 00D7ACAF23EABBC800FBE4A7 /* BugsnagSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D7ACAE23EABBC800FBE4A7 /* BugsnagSwiftTests.swift */; }; + 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 */; }; @@ -412,6 +413,8 @@ 000E6EA023D8AC8C009D8194 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 000E6EA123D8AC8C009D8194 /* VERSION */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = VERSION; path = ../VERSION; sourceTree = ""; }; 000E6EA223D8AC8C009D8194 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; }; + 00D7ACAC23E9C63000FBE4A7 /* BugsnagTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagTests.m; path = ../../Tests/BugsnagTests.m; sourceTree = ""; }; + 00D7ACAE23EABBC800FBE4A7 /* BugsnagSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugsnagSwiftTests.swift; sourceTree = ""; }; 4B3B193422CA7B0900475354 /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictSetSafeObjectTest.m; path = ../../Tests/BugsnagCollectionsBSGDictSetSafeObjectTest.m; sourceTree = ""; }; 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BugsnagEventFromKSCrashReportTest.m; sourceTree = ""; }; 4B775FCE22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictInsertIfNotNilTest.m; path = ../../Tests/BugsnagCollectionsBSGDictInsertIfNotNilTest.m; sourceTree = ""; }; @@ -638,6 +641,7 @@ isa = PBXGroup; children = ( 000E6E9D23D8690F009D8194 /* BugsnagSwiftConfigurationTests.swift */, + 00D7ACAE23EABBC800FBE4A7 /* BugsnagSwiftTests.swift */, ); path = "Swift Tests"; sourceTree = ""; @@ -755,6 +759,7 @@ 000E6E9B23D84DB1009D8194 /* BugsnagTestConstants.h */, 000E6E9C23D8690E009D8194 /* Tests-Bridging-Header.h */, 000DF29323DB4B4900A883CE /* TestConstants.m */, + 00D7ACAC23E9C63000FBE4A7 /* BugsnagTests.m */, ); name = Tests; path = BugsnagTests; @@ -1244,6 +1249,7 @@ E78C1EFE1FCC778700B976D3 /* BugsnagUserTest.m in Sources */, 8A2C8F911C6BBFDD00846019 /* BugsnagSinkTests.m in Sources */, E784D2551FD70B3B004B01E1 /* KSCrashState_Tests.m in Sources */, + 00D7ACAD23E9C63000FBE4A7 /* BugsnagTests.m in Sources */, 8A2C8F901C6BBFDD00846019 /* BugsnagEventTests.m in Sources */, E77316E31F73E89E00A14F06 /* BugsnagHandledStateTest.m in Sources */, E70EE0961FD7071F00FA745C /* FileBasedTestCase.m in Sources */, @@ -1262,6 +1268,7 @@ F4295995C3259BF7D9730BC4 /* BugsnagKSCrashSysInfoParserTest.m in Sources */, E70E52152216E41C00A590AB /* BugsnagSessionTrackerStopTest.m in Sources */, F4295F017754324FD52CCE46 /* RegisterErrorDataTest.m in Sources */, + 00D7ACAF23EABBC800FBE4A7 /* BugsnagSwiftTests.swift in Sources */, F42952D83435C02F8D891C40 /* BugsnagThreadTest.m in Sources */, 4B47970A22A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m in Sources */, ); diff --git a/iOS/BugsnagTests/Swift Tests/BugsnagSwiftTests.swift b/iOS/BugsnagTests/Swift Tests/BugsnagSwiftTests.swift new file mode 100644 index 000000000..0b424dd9d --- /dev/null +++ b/iOS/BugsnagTests/Swift Tests/BugsnagSwiftTests.swift @@ -0,0 +1,36 @@ +// +// BugsnagSwiftTests.swift +// Tests +// +// Created by Robin Macharg on 05/02/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// +// Swift unit tests of global Bugsnag behaviour + +import XCTest + +class BugsnagSwiftTests: XCTestCase { + + /** + * Confirm that the method is exposed to Swift correctly + */ + func testAddMetadataToSectionIsExposedToSwiftCorrectly() { + do { + if let configuration = try BugsnagConfiguration(DUMMY_APIKEY_32CHAR_1) { + Bugsnag.start(with: configuration) + Bugsnag.addMetadata("mySection1", key: "myKey1", value: "myValue1") + + let exception1 = NSException(name: NSExceptionName(rawValue: "exception1"), reason: "reason1", userInfo: nil) + + Bugsnag.notify(exception1) { (event) in + // Arbitrary test, replicating the ObjC one + let value = (event.metaData["mySection1"] as! [String : Any])["myKey1"] as! String + XCTAssertEqual(value, "myValue1") + } + } + } + catch let e as NSError { + print(e) + } + } +}