diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index 85792944b..7f5571300 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -17,21 +17,24 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: + # PLAT-11155: App hang scenarios run on BrowserStack + - "--exclude=features/app_hangs.feature" - "--exclude=features/[e-z].*.feature$" - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_15" - "--no-tunnel" - "--aws-public-ip" + - "--fail-fast" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ':bitbar: iOS 15 E2E tests batch 2' @@ -41,7 +44,7 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar @@ -49,13 +52,14 @@ steps: service-ports: true command: - "--exclude=features/[a-d].*.feature$" - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_15" - "--no-tunnel" - "--aws-public-ip" + - "--fail-fast" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ':bitbar: iOS 14 E2E tests batch 1' @@ -66,23 +70,24 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_14" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + # PLAT-11155: App hang scenarios run on BrowserStack + - "--exclude=features/app_hangs.feature" - "--exclude=features/[e-z].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -97,23 +102,22 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_14" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" - "--exclude=features/[a-d].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -128,23 +132,24 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_13" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + # PLAT-11155: App hang scenarios run on BrowserStack + - "--exclude=features/app_hangs.feature" - "--exclude=features/[e-z].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -159,23 +164,22 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_13" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" - "--exclude=features/[a-d].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -190,23 +194,24 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_12" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + # PLAT-11155: App hang scenarios run on BrowserStack + - "--exclude=features/app_hangs.feature" - "--exclude=features/[e-z].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -221,23 +226,22 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_12" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" - "--exclude=features/[a-d].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -247,7 +251,124 @@ steps: # # BrowserStack # + # PLAT-11155: App hang tests run on BrowserStack (Appium 1.x) for now + - label: ':browserstack: iOS 15 app hang tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 10 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + command: + - "--app=@build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_15" + - "--appium-version=1.21.0" + - "--fail-fast" + - "features/app_hangs.feature" + concurrency: 5 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + # PLAT-11155: App hang tests run on BrowserStack (Appium 1.x) for now + - label: ':browserstack: iOS 14 app hang tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 10 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + command: + - "--app=@build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_14" + - "--appium-version=1.21.0" + - "--fail-fast" + - "features/app_hangs.feature" + concurrency: 5 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + # PLAT-11155: App hang tests run on BrowserStack (Appium 1.x) for now + - label: ':browserstack: iOS 13 app hang tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 10 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + command: + - "--app=@build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_13" + - "--appium-version=1.21.0" + - "--fail-fast" + - "features/app_hangs.feature" + concurrency: 5 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + # PLAT-11155: App hang tests run on BrowserStack (Appium 1.x) for now + - label: ':browserstack: iOS 12 app hang tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 10 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + command: + - "--app=@build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_12" + - "--appium-version=1.21.0" + - "--fail-fast" + - "features/app_hangs.feature" + concurrency: 5 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + - label: ':browserstack: iOS 11 E2E tests batch 1' + skip: "https://smartbear.atlassian.net/browse/PLAT-11154" depends_on: - cocoa_fixture # More time than other steps as the BrowserStack iOS 11 devices seem particularly unstable and @@ -257,21 +378,20 @@ steps: queue: opensource plugins: artifacts#v1.5.0: - download: "features/fixtures/ios/output/ipa_url.txt" + download: "features/fixtures/ios/output/ipa_url_bs.txt" upload: "maze_output/failed/**/*" docker-compose#v3.7.0: pull: cocoa-maze-runner-legacy run: cocoa-maze-runner-legacy command: - - "--app=@build/ipa_url.txt" + - "--app=@build/ipa_url_bs.txt" - "--farm=bs" - "--device=IOS_11_0_IPHONE_8_PLUS" - "--appium-version=1.16.0" - "--fail-fast" - "--exclude=features/[e-z].*.feature$" - - "--order=random" concurrency: 5 - concurrency_group: browserstack-app + concurrency_group: 'browserstack-app' concurrency_method: eager retry: automatic: @@ -279,6 +399,7 @@ steps: limit: 2 - label: ':browserstack: iOS 11 E2E tests batch 2' + skip: "https://smartbear.atlassian.net/browse/PLAT-11154" depends_on: - cocoa_fixture # More time than other steps as the BrowserStack iOS 11 devices seem particularly unstable and @@ -288,21 +409,20 @@ steps: queue: opensource plugins: artifacts#v1.5.0: - download: "features/fixtures/ios/output/ipa_url.txt" + download: "features/fixtures/ios/output/ipa_url_bs.txt" upload: "maze_output/failed/**/*" docker-compose#v3.7.0: pull: cocoa-maze-runner-legacy run: cocoa-maze-runner-legacy command: - - "--app=@build/ipa_url.txt" + - "--app=@build/ipa_url_bs.txt" - "--farm=bs" - "--device=IOS_11_0_IPHONE_8_PLUS" - "--appium-version=1.16.0" - "--fail-fast" - "--exclude=features/[a-d].*.feature$" - - "--order=random" concurrency: 5 - concurrency_group: browserstack-app + concurrency_group: 'browserstack-app' concurrency_method: eager retry: automatic: @@ -324,7 +444,6 @@ steps: - bundle exec maze-runner --os=macos --fail-fast - --order=random - label: 'ARM macOS 12 E2E tests' depends_on: @@ -343,7 +462,6 @@ steps: - bundle exec maze-runner --os=macos --fail-fast - --order=random - label: 'macOS 10.13 E2E tests' depends_on: @@ -360,7 +478,6 @@ steps: - bundle exec maze-runner --os=macos --fail-fast - --order=random - label: 'macOS 10.14 E2E tests' depends_on: @@ -377,7 +494,6 @@ steps: - bundle exec maze-runner --os=macos --fail-fast - --order=random ############################################################################## # diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 1735d6220..10b2f567d 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -11,20 +11,24 @@ steps: key: cocoa_fixture timeout_in_minutes: 30 agents: - queue: macos-12-arm + queue: macos-13-arm + env: + DEVELOPER_DIR: /Applications/Xcode14.3.app artifact_paths: - features/fixtures/ios/output/iOSTestApp.ipa - features/fixtures/macos/output/macOSTestApp.zip - - features/fixtures/ios/output/ipa_url.txt + - features/fixtures/ios/output/ipa_url_bb.txt + - features/fixtures/ios/output/ipa_url_bs.txt commands: - bundle install - make test-fixtures - - bundle exec upload-app --app=./features/fixtures/ios/output/iOSTestApp.ipa --app-id-file=./features/fixtures/ios/output/ipa_url.txt + - bundle exec upload-app --farm=bb --app=./features/fixtures/ios/output/iOSTestApp.ipa --app-id-file=./features/fixtures/ios/output/ipa_url_bb.txt + - bundle exec upload-app --farm=bs --app=./features/fixtures/ios/output/iOSTestApp.ipa --app-id-file=./features/fixtures/ios/output/ipa_url_bs.txt - label: Static framework and Swift Package Manager builds timeout_in_minutes: 10 agents: - queue: macos-12-arm + queue: macos-13-arm commands: - make build_swift - make build_ios_static @@ -32,7 +36,7 @@ steps: - label: Carthage timeout_in_minutes: 15 agents: - queue: macos-12-arm + queue: macos-13-arm commands: - ./scripts/build-carthage.sh plugins: @@ -89,6 +93,15 @@ steps: artifact_paths: - logs/* + - label: iOS 17 unit tests + timeout_in_minutes: 10 + agents: + queue: macos-13-arm + commands: + - ./scripts/run-unit-tests.sh PLATFORM=iOS OS=17.0 + artifact_paths: + - logs/* + - label: iOS 15 unit tests timeout_in_minutes: 10 agents: @@ -180,24 +193,24 @@ steps: - logs/* - label: watchOS 8 unit tests - timeout_in_minutes: 10 + timeout_in_minutes: 60 agents: queue: opensource-arm-mac-cocoa-12 env: - DEVELOPER_DIR: /Applications/Xcode13.4.app + DEVELOPER_DIR: /Applications/Xcode14.0.app commands: - - ./scripts/run-unit-tests.sh PLATFORM=watchOS OS=8.3 + - ./scripts/run-unit-tests.sh PLATFORM=watchOS OS=8.3 SDK=watchsimulator9.0 artifact_paths: - logs/* - label: watchOS 7 unit tests - timeout_in_minutes: 10 + timeout_in_minutes: 60 agents: queue: opensource-arm-mac-cocoa-12 env: - DEVELOPER_DIR: /Applications/Xcode13.4.app + DEVELOPER_DIR: /Applications/Xcode14.0.app commands: - - ./scripts/run-unit-tests.sh PLATFORM=watchOS OS=7.4 + - ./scripts/run-unit-tests.sh PLATFORM=watchOS OS=7.4 SDK=watchsimulator9.0 artifact_paths: - logs/* @@ -219,7 +232,6 @@ steps: features/barebone_tests.feature --os=macos --fail-fast - --order=random - label: 'macOS 10.15 E2E tests' depends_on: @@ -236,7 +248,6 @@ steps: - bundle exec maze-runner --os=macos --fail-fast - --order=random - label: 'ARM macOS 12 barebones E2E tests' depends_on: @@ -256,7 +267,6 @@ steps: features/barebone_tests.feature --os=macos --fail-fast - --order=random - label: 'macOS 12 stress test' timeout_in_minutes: 3 @@ -293,23 +303,24 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_16" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" + # PLAT-11155: App hang scenarios run on BrowserStack + - "--exclude=features/app_hangs.feature" - "--exclude=features/[e-z].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -324,23 +335,51 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_16" - "--no-tunnel" - "--aws-public-ip" - "--fail-fast" - "--exclude=features/[a-d].*.feature$" - - "--order=random" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + # PLAT-11155: App hang tests run on BrowserStack (Appium 1.x) for now + - label: ':browserstack: iOS 16 app hang tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 10 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + command: + - "--app=@build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_16" + - "--appium-version=1.21.0" + - "--fail-fast" + - "features/app_hangs.feature" + concurrency: 5 + concurrency_group: 'browserstack-app' concurrency_method: eager retry: automatic: @@ -355,14 +394,14 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_15" - "--no-tunnel" @@ -370,7 +409,7 @@ steps: - "--fail-fast" - "features/barebone_tests.feature" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -385,14 +424,14 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_14" - "--no-tunnel" @@ -400,7 +439,7 @@ steps: - "--fail-fast" - "features/barebone_tests.feature" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -415,14 +454,14 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_13" - "--no-tunnel" @@ -430,7 +469,7 @@ steps: - "--fail-fast" - "features/barebone_tests.feature" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -445,14 +484,14 @@ steps: queue: opensource plugins: artifacts#v1.9.0: - download: "features/fixtures/ios/output/iOSTestApp.ipa" + download: "features/fixtures/ios/output/ipa_url_bb.txt" upload: "maze_output/failed/**/*" docker-compose#v4.7.0: pull: cocoa-maze-runner-bitbar run: cocoa-maze-runner-bitbar service-ports: true command: - - "--app=/app/build/iOSTestApp.ipa" + - "--app=@/app/build/ipa_url_bb.txt" - "--farm=bb" - "--device=IOS_12" - "--no-tunnel" @@ -460,7 +499,7 @@ steps: - "--fail-fast" - "features/barebone_tests.feature" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager retry: automatic: @@ -470,7 +509,70 @@ steps: # # BrowserStack # + - label: ':browserstack: iOS 17 E2E tests batch 1' + depends_on: + - cocoa_fixture + timeout_in_minutes: 60 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + service-ports: true + command: + - "--app=@/app/build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_17" + - "--appium-version=1.18.0" + - "--a11y-locator" + - "--fail-fast" + - "--exclude=features/[e-z].*.feature$" + - "--order=random" + concurrency: 25 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + - label: ':browserstack: iOS 17 E2E tests batch 2' + depends_on: + - cocoa_fixture + timeout_in_minutes: 60 + agents: + queue: opensource + plugins: + artifacts#v1.5.0: + download: "features/fixtures/ios/output/ipa_url_bs.txt" + upload: "maze_output/failed/**/*" + docker-compose#v3.7.0: + pull: cocoa-maze-runner + run: cocoa-maze-runner + service-ports: true + command: + - "--app=@/app/build/ipa_url_bs.txt" + - "--farm=bs" + - "--device=IOS_17" + - "--appium-version=1.18.0" + - "--a11y-locator" + - "--fail-fast" + - "--exclude=features/[a-d].*.feature$" + - "--order=random" + concurrency: 25 + concurrency_group: 'browserstack-app' + concurrency_method: eager + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + - label: ':browserstack: iOS 11 barebone tests' + skip: "https://smartbear.atlassian.net/browse/PLAT-11154" depends_on: - cocoa_fixture timeout_in_minutes: 60 @@ -478,19 +580,20 @@ steps: queue: opensource plugins: artifacts#v1.5.0: - download: "features/fixtures/ios/output/ipa_url.txt" + download: "features/fixtures/ios/output/ipa_url_bs.txt" upload: "maze_output/failed/**/*" docker-compose#v3.7.0: pull: cocoa-maze-runner run: cocoa-maze-runner command: - - "--app=@build/ipa_url.txt" + - "--app=@build/ipa_url_bs.txt" - "--farm=bs" - "--device=IOS_11_0_IPHONE_8_PLUS" - "--appium-version=1.16.0" + - "--fail-fast" - "features/barebone_tests.feature" concurrency: 5 - concurrency_group: browserstack-app + concurrency_group: 'browserstack-app' concurrency_method: eager retry: automatic: @@ -505,20 +608,20 @@ steps: queue: opensource plugins: artifacts#v1.5.0: - download: "features/fixtures/ios/output/ipa_url.txt" + download: "features/fixtures/ios/output/ipa_url_bs.txt" upload: "maze_output/failed/**/*" docker-compose#v3.7.0: pull: cocoa-maze-runner run: cocoa-maze-runner command: - - "--app=@build/ipa_url.txt" + - "--app=@build/ipa_url_bs.txt" - "--farm=bs" - "--device=IOS_10" - "--appium-version=1.15.0" - "--fail-fast" - "features/barebone_tests.feature" concurrency: 5 - concurrency_group: browserstack-app + concurrency_group: 'browserstack-app' concurrency_method: eager retry: automatic: diff --git a/.github/workflows/downstream_updates.yml b/.github/workflows/downstream_updates.yml new file mode 100644 index 000000000..a299295a4 --- /dev/null +++ b/.github/workflows/downstream_updates.yml @@ -0,0 +1,32 @@ +name: downstream-updates + +on: + release: + types: [released] + workflow_dispatch: + inputs: + target_version: + description: 'Version of the submodule to update downstream repos to' + required: true + type: string + +jobs: + update-dependencies: + runs-on: ubuntu-latest + env: + RELEASE_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.target_version || github.event.release.tag_name }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + strategy: + matrix: + downstream_repo: ['bugsnag/bugsnag-unity'] + steps: + - name: Install libcurl4-openssl-dev and net-tools + run: | + sudo apt-get update + sudo apt-get install libcurl4-openssl-dev net-tools + + - run: > + curl -X POST https://api.github.com/repos/${{ matrix.downstream_repo }}/dispatches + -H 'Content-Type: application/json' + -H "Authorization: Bearer $GITHUB_TOKEN" + -d '{"event_type":"update-dependency","client_payload": {"target_submodule":"bugsnag-cocoa", "target_version": "$RELEASE_VERSION"}}' diff --git a/.gitignore b/.gitignore index 001e898bd..da7e5f018 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ Package.resolved /docs/ /infer-out /oclint.json +bb.ready diff --git a/.jazzy.yaml b/.jazzy.yaml index 7e5b8e596..8c9ad4004 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.27.2/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.27.3/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.27.2" +module_version: "6.27.3" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index a4018ecd8..a63e40143 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.27.2", + "version": "6.27.3", "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.27.2" + "tag": "v6.27.3" }, "ios": { "frameworks": [ diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index d1843abe5..2907142e6 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -721,6 +721,14 @@ 01FF490728BF8B7B001F817B /* BugsnagInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 01FF490528BF8B7B001F817B /* BugsnagInternals.h */; }; 01FF490828BF8B7B001F817B /* BugsnagInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 01FF490528BF8B7B001F817B /* BugsnagInternals.h */; }; 01FF490928BF8B7B001F817B /* BugsnagInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 01FF490528BF8B7B001F817B /* BugsnagInternals.h */; }; + 093EB6602AFE447E006EB7E3 /* Swizzle.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */; }; + 093EB6612AFE447E006EB7E3 /* Swizzle.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */; }; + 093EB6622AFE447E006EB7E3 /* Swizzle.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */; }; + 093EB6632AFE447E006EB7E3 /* Swizzle.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */; }; + 093EB6662AFE4580006EB7E3 /* BSGTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */; }; + 093EB6672AFE4580006EB7E3 /* BSGTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */; }; + 093EB6682AFE4580006EB7E3 /* BSGTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */; }; + 093EB6692AFE4580006EB7E3 /* BSGTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */; }; 3A700A9424A63ABC0068CD1B /* BugsnagThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A700A8024A63A8E0068CD1B /* BugsnagThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3A700A9524A63AC50068CD1B /* BugsnagSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A700A8124A63A8E0068CD1B /* BugsnagSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3A700A9624A63AC60068CD1B /* BugsnagStackframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A700A8224A63A8E0068CD1B /* BugsnagStackframe.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1539,6 +1547,10 @@ 01E8765D256684E700F4B70A /* URLSessionMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = URLSessionMock.m; sourceTree = ""; }; 01F9FCB528929336005EDD8C /* BSGSerializationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGSerializationTests.m; sourceTree = ""; }; 01FF490528BF8B7B001F817B /* BugsnagInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagInternals.h; sourceTree = ""; }; + 093EB65E2AFE447E006EB7E3 /* Swizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Swizzle.h; sourceTree = ""; }; + 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Swizzle.mm; sourceTree = ""; }; + 093EB6642AFE4580006EB7E3 /* BSGTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGTestCase.h; sourceTree = ""; }; + 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BSGTestCase.mm; sourceTree = ""; }; 3A700A8024A63A8E0068CD1B /* BugsnagThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagThread.h; sourceTree = ""; }; 3A700A8124A63A8E0068CD1B /* BugsnagSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagSession.h; sourceTree = ""; }; 3A700A8224A63A8E0068CD1B /* BugsnagStackframe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagStackframe.h; sourceTree = ""; }; @@ -1934,8 +1946,6 @@ 00AD1C7F24869B0E00A27979 /* BugsnagTests */ = { isa = PBXGroup; children = ( - CBEC893E2A4ACD230088A3CE /* FileBasedTest.h */, - CBEC893F2A4ACD230088A3CE /* FileBasedTest.m */, 019480D32625F3EB00E833ED /* BSGAppKitTests.m */, 008966BD2486D43500DC48C2 /* BSGClientObserverTests.m */, 00896A3F2486DBDD00DC48C2 /* BSGConfigurationBuilderTests.m */, @@ -1953,6 +1963,8 @@ 01F9FCB528929336005EDD8C /* BSGSerializationTests.m */, CB6419AA25A73E8C00613D25 /* BSGStorageMigratorV0V1Tests.m */, 017DCF9A287422BB000ECB22 /* BSGTelemetryTests.m */, + 093EB6642AFE4580006EB7E3 /* BSGTestCase.h */, + 093EB6652AFE4580006EB7E3 /* BSGTestCase.mm */, 01DE903B26CEAF9E00455213 /* BSGUtilsTests.m */, CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */, E701FA9E2490EF4A008D842F /* BugsnagApiValidationTest.m */, @@ -1995,9 +2007,13 @@ E701FAAE2490EFE8008D842F /* ConfigurationApiValidationTest.m */, 01BDB21425DEC02900A91FAF /* Data */, E701FAAA2490EFD9008D842F /* EventApiValidationTest.m */, + CBEC893E2A4ACD230088A3CE /* FileBasedTest.h */, + CBEC893F2A4ACD230088A3CE /* FileBasedTest.m */, 00E636C324878FFC006CBF1A /* Info.plist */, 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */, 008966B72486D43500DC48C2 /* report.json */, + 093EB65E2AFE447E006EB7E3 /* Swizzle.h */, + 093EB65F2AFE447E006EB7E3 /* Swizzle.mm */, 004E35392487B375007FBAE4 /* Tests-Bridging-Header.h */, CBA22499251E429C00B87416 /* TestSupport.h */, CBA2249A251E429C00B87416 /* TestSupport.m */, @@ -3149,6 +3165,7 @@ 0089679F2486D43700DC48C2 /* KSCrashSentry_Tests.m in Sources */, 008967872486D43700DC48C2 /* KSCrashSentry_NSException_Tests.m in Sources */, 0089679C2486D43700DC48C2 /* KSFileUtils_Tests.m in Sources */, + 093EB6602AFE447E006EB7E3 /* Swizzle.mm in Sources */, 008966EE2486D43700DC48C2 /* BugsnagClientPayloadInfoTest.m in Sources */, 010F80C228645B4200D6569E /* BSGDefinesTests.m in Sources */, 01BDB1F525DEBFB200A91FAF /* BSGEventUploadKSCrashReportOperationTests.m in Sources */, @@ -3168,6 +3185,7 @@ 008967152486D43700DC48C2 /* BugsnagCollectionsTests.m in Sources */, 01E8765E256684E700F4B70A /* URLSessionMock.m in Sources */, 008967AB2486D43700DC48C2 /* BSG_KSMachTests.m in Sources */, + 093EB6662AFE4580006EB7E3 /* BSGTestCase.mm in Sources */, 0089672A2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */, 01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, 0163BF5925823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */, @@ -3315,6 +3333,7 @@ 008967822486D43700DC48C2 /* KSSystemInfo_Tests.m in Sources */, 008967612486D43700DC48C2 /* BugsnagBreadcrumbsTest.m in Sources */, 01DE903D26CEAF9E00455213 /* BSGUtilsTests.m in Sources */, + 093EB6672AFE4580006EB7E3 /* BSGTestCase.mm in Sources */, CB156242270707740097334C /* KSCrashNames_Test.m in Sources */, 008967012486D43700DC48C2 /* BugsnagEventPersistLoadTest.m in Sources */, 0089671C2486D43700DC48C2 /* BugsnagSessionTest.m in Sources */, @@ -3341,6 +3360,7 @@ 004E353B2487B3B3007FBAE4 /* BugsnagSwiftPublicAPITests.swift in Sources */, 0089677C2486D43700DC48C2 /* RFC3339DateTool_Tests.m in Sources */, CBEC89412A4ACD240088A3CE /* FileBasedTest.m in Sources */, + 093EB6612AFE447E006EB7E3 /* Swizzle.mm in Sources */, 01A2958728B667C2005FCC8C /* BSGNetworkBreadcrumbTests.m in Sources */, 008967552486D43700DC48C2 /* BugsnagOnCrashTest.m in Sources */, 008967A02486D43700DC48C2 /* KSCrashSentry_Tests.m in Sources */, @@ -3481,6 +3501,7 @@ 01B6BB7E25D5777F00FC4DE6 /* BugsnagSwiftPublicAPITests.swift in Sources */, 0089677A2486D43700DC48C2 /* BSG_KSMachHeadersTests.m in Sources */, 0089672C2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */, + 093EB6682AFE4580006EB7E3 /* BSGTestCase.mm in Sources */, 008966F32486D43700DC48C2 /* BugsnagMetadataRedactionTest.m in Sources */, 008967382486D43700DC48C2 /* BugsnagMetadataTests.m in Sources */, 008967832486D43700DC48C2 /* KSSystemInfo_Tests.m in Sources */, @@ -3514,6 +3535,7 @@ 008967442486D43700DC48C2 /* BugsnagSessionTrackerStopTest.m in Sources */, CB26E9BC28350E0C005A1865 /* UISceneStub.m in Sources */, 008967982486D43700DC48C2 /* KSCrashState_Tests.m in Sources */, + 093EB6622AFE447E006EB7E3 /* Swizzle.mm in Sources */, 008967772486D43700DC48C2 /* XCTestCase+KSCrash.m in Sources */, 01A2958828B667C2005FCC8C /* BSGNetworkBreadcrumbTests.m in Sources */, CBEC89422A4ACD240088A3CE /* FileBasedTest.m in Sources */, @@ -3748,7 +3770,9 @@ CB28F0B828294DE1003AB200 /* BSGConfigurationBuilderTests.m in Sources */, CB28F0DB282A4BA6003AB200 /* BugsnagMetadataTests.m in Sources */, CB28F0B028294D4F003AB200 /* KSFileUtils_Tests.m in Sources */, + 093EB6632AFE447E006EB7E3 /* Swizzle.mm in Sources */, CB28F0DC282A4BEE003AB200 /* BugsnagSessionTrackerTest.m in Sources */, + 093EB6692AFE4580006EB7E3 /* BSGTestCase.mm in Sources */, CB28F0B728294DE1003AB200 /* BSGFeatureFlagStoreTests.m in Sources */, 010F80C528645B4200D6569E /* BSGDefinesTests.m in Sources */, CB28F0A028294D44003AB200 /* BSG_KSFileTests.m in Sources */, diff --git a/Bugsnag/BugsnagInternals.h b/Bugsnag/BugsnagInternals.h index 7a71c091e..76c00bea4 100644 --- a/Bugsnag/BugsnagInternals.h +++ b/Bugsnag/BugsnagInternals.h @@ -231,6 +231,8 @@ typedef void (^ BSGClientObserver)(BSGClientObserverEvent event, _Nullable id va - (NSDictionary *)toJson; +- (NSDictionary *)toJsonWithNSNulls; + @end #pragma mark - diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 5cf220a98..6a187b3fe 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -560,7 +560,7 @@ - (BugsnagUser *)user { - (void)setUser:(NSString *)userId withEmail:(NSString *)email andName:(NSString *)name { @synchronized (self.configuration) { [self.configuration setUser:userId withEmail:email andName:name]; - [self.state addMetadata:[self.configuration.user toJson] toSection:BSGKeyUser]; + [self.state addMetadata:[self.configuration.user toJsonWithNSNulls] toSection:BSGKeyUser]; if (self.observer) { self.observer(BSGClientObserverUpdateUser, self.user); } diff --git a/Bugsnag/Helpers/BSGDefines.h b/Bugsnag/Helpers/BSGDefines.h index cf60fb14e..25ac28bf2 100644 --- a/Bugsnag/Helpers/BSGDefines.h +++ b/Bugsnag/Helpers/BSGDefines.h @@ -19,7 +19,7 @@ #define BSG_HAVE_REACHABILITY_WWAN ( TARGET_OS_IOS || TARGET_OS_TV ) #define BSG_HAVE_SIGNAL (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV ) #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_SYSCALL (TARGET_OS_IOS || TARGET_OS_TV ) #define BSG_HAVE_UIDEVICE __has_include() #define BSG_HAVE_WINDOW (TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_TV ) diff --git a/Bugsnag/Helpers/BSGRunContext.h b/Bugsnag/Helpers/BSGRunContext.h index a69fd0273..a6a02d552 100644 --- a/Bugsnag/Helpers/BSGRunContext.h +++ b/Bugsnag/Helpers/BSGRunContext.h @@ -19,7 +19,7 @@ // During development this is not strictly necessary since last run's data will // not be loaded if the struct's size has changed. // -#define BSGRUNCONTEXT_VERSION 4 +#define BSGRUNCONTEXT_VERSION 5 struct BSGRunContext { long structVersion; @@ -50,6 +50,7 @@ struct BSGRunContext { unsigned long long memoryAvailable; unsigned long long memoryFootprint; unsigned long long memoryLimit; + char bundleVersion[32]; // Won't actually get this long but just to be sure. }; /// Information about the current run of the app / process. diff --git a/Bugsnag/Helpers/BSGRunContext.m b/Bugsnag/Helpers/BSGRunContext.m index 5e9f7a5bd..1af6767d3 100644 --- a/Bugsnag/Helpers/BSGRunContext.m +++ b/Bugsnag/Helpers/BSGRunContext.m @@ -63,12 +63,21 @@ static void InitRunContext(void) { } bsg_runContext->bootTime = GetBootTime(); - + + // Make sure the images list is populated. + bsg_mach_headers_initialize(); + BSG_Mach_Header_Info *image = bsg_mach_headers_get_main_image(); if (image && image->uuid) { uuid_copy(bsg_runContext->machoUUID, image->uuid); } - + + NSString *bundleVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; + const char *bundleVersionStr = (const char*)[bundleVersion cStringUsingEncoding:NSUTF8StringEncoding]; + if (bundleVersionStr != nil) { + bsg_safe_strncpy(bsg_runContext->bundleVersion, bundleVersionStr, sizeof(bsg_runContext->bundleVersion)); + } + if ([NSThread isMainThread]) { bsg_runContext->isActive = GetIsActive(); } else { @@ -109,8 +118,15 @@ static bool GetIsActive(void) { #endif #if TARGET_OS_WATCH - WKExtension *ext = [WKExtension sharedExtension]; - return ext && ext.applicationState == WKApplicationStateActive; + if ([BSG_KSSystemInfo isRunningInAppExtension]) { + WKExtension *ext = [WKExtension sharedExtension]; + return ext && ext.applicationState == WKApplicationStateActive; + } else if (@available(watchOS 7.0, *)) { + WKApplication *app = [WKApplication sharedApplication]; + return app && app.applicationState == WKApplicationStateActive; + } else { + return true; + } #endif } @@ -167,8 +183,15 @@ static bool GetIsForeground(void) { #endif #if TARGET_OS_WATCH - WKExtension *ext = [WKExtension sharedExtension]; - return ext && ext.applicationState != WKApplicationStateBackground; + if ([BSG_KSSystemInfo isRunningInAppExtension]) { + WKExtension *ext = [WKExtension sharedExtension]; + return ext && ext.applicationState != WKApplicationStateBackground; + } else if (@available(watchOS 7.0, *)) { + WKApplication *app = [WKApplication sharedApplication]; + return app && app.applicationState == WKApplicationStateBackground; + } else { + return true; + } #endif } @@ -470,8 +493,13 @@ bool BSGRunContextWasKilled(void) { if (bsg_lastRunContext->bootTime != bsg_runContext->bootTime) { return NO; // The app may have been terminated due to the reboot } - + // Ignore unexpected terminations due to the app being upgraded + if (strncmp(bsg_lastRunContext->bundleVersion, + bsg_runContext->bundleVersion, + sizeof(bsg_runContext->bundleVersion)) != 0) { + return NO; + } if (uuid_compare(bsg_lastRunContext->machoUUID, bsg_runContext->machoUUID)) { return NO; } @@ -499,10 +527,13 @@ bool BSGRunContextWasKilled(void) { #define SIZEOF_STRUCT sizeof(struct BSGRunContext) -static struct BSGRunContext fallback; -struct BSGRunContext *bsg_runContext = &fallback; +static struct BSGRunContext bsg_runContext_fallback; +struct BSGRunContext *bsg_runContext = &bsg_runContext_fallback; -const struct BSGRunContext *bsg_lastRunContext; +static struct BSGRunContext bsg_lastRunContext_fallback = { + .structVersion = ~0, +}; +const struct BSGRunContext *bsg_lastRunContext = &bsg_lastRunContext_fallback; /// Opens the file and disables content protection, returning -1 on error. static int OpenFile(NSString *_Nonnull path) { diff --git a/Bugsnag/Helpers/BSGUtils.h b/Bugsnag/Helpers/BSGUtils.h index 06cb3d473..d462290fa 100644 --- a/Bugsnag/Helpers/BSGUtils.h +++ b/Bugsnag/Helpers/BSGUtils.h @@ -39,6 +39,12 @@ static inline NSString * _Nullable BSGStringFromClass(Class _Nullable cls) { return cls ? NSStringFromClass((Class _Nonnull)cls) : nil; } +/** + * Copy characters from src to dst, up to a maximum of length bytes (including the NUL terminator). + * Unlike strncpy, this function always ensures that dst is NUL terminated (if length > 0). + */ +void bsg_safe_strncpy(char *dst, const char *src, size_t length); + NS_ASSUME_NONNULL_END __END_DECLS diff --git a/Bugsnag/Helpers/BSGUtils.m b/Bugsnag/Helpers/BSGUtils.m index ae2608ec4..04e8d9863 100644 --- a/Bugsnag/Helpers/BSGUtils.m +++ b/Bugsnag/Helpers/BSGUtils.m @@ -10,6 +10,13 @@ #import "BugsnagLogger.h" +void bsg_safe_strncpy(char *dst, const char *src, size_t length) { + if (length > 0) { + strncpy(dst, src, length); + dst[length-1] = 0; + } +} + char *_Nullable BSGCStringWithData(NSData *_Nullable data) { char *buffer; if (data.length && (buffer = calloc(1, data.length + 1))) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h index 05e9cb7fe..f9f1b23ed 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h @@ -76,7 +76,7 @@ static inline bool bsg_local_is_insert_libraries_env_var(const char* str) { // - Use pointers for output parameters, with labels that identify them as such. // - Beware of global consts or defines bleeding through. -#if TARGET_CPU_ARM64 +#if TARGET_CPU_ARM64 && !TARGET_OS_OSX #define BSG_HAS_CUSTOM_SYSCALL 1 // ARM64 3-parameter syscall @@ -105,7 +105,7 @@ static inline bool bsg_local_is_insert_libraries_env_var(const char* str) { } \ } while(0) -#elif TARGET_CPU_X86_64 && defined(__GCC_ASM_FLAG_OUTPUTS__) +#elif TARGET_CPU_X86_64 && defined(__GCC_ASM_FLAG_OUTPUTS__) && !TARGET_OS_OSX #define BSG_HAS_CUSTOM_SYSCALL 1 // X86_64 3-parameter syscall diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h index b21f4f7e7..a4876fb3c 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h @@ -30,14 +30,14 @@ #ifndef HDR_BSG_KSCrashC_h #define HDR_BSG_KSCrashC_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_KSCrashContext.h" #include +#ifdef __cplusplus +extern "C" { +#endif + /** Initialize the KSCrash system. Call this once, before any other function. * Note: This gets called automatically by [BSG_KSCrash sharedInstance]. */ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h index d55aaa6a0..994be9355 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h @@ -30,10 +30,6 @@ #ifndef HDR_BSG_KSCrashContext_h #define HDR_BSG_KSCrashContext_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_KSCrashReportWriter.h" #include "BSG_KSCrashSentry.h" #include "BSG_KSCrashState.h" @@ -41,6 +37,10 @@ extern "C" { #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { /** A unique identifier (UUID). */ char *crashID; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h index 3e05a6b48..f93713dde 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h @@ -1,5 +1,6 @@ #ifndef HDR_BSG_KSCrashIdentifier_h #define HDR_BSG_KSCrashIdentifier_h + #include #ifdef __cplusplus diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashNames.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashNames.h index 3b62ffe36..c2ec5e26c 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashNames.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashNames.h @@ -9,12 +9,12 @@ #ifndef BSG_KSCrashNames_h #define BSG_KSCrashNames_h +#include + #ifdef __cplusplus extern "C" { #endif -#include - const char *bsg_kscrashthread_state_name(integer_t state); #ifdef __cplusplus diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.h index a6e690ae6..adcd6531c 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.h @@ -30,12 +30,12 @@ #ifndef HDR_BSG_KSCrashReport_h #define HDR_BSG_KSCrashReport_h +#include "BSG_KSCrashContext.h" + #ifdef __cplusplus extern "C" { #endif -#include "BSG_KSCrashContext.h" - /** Write a standard crash report to a file. * * @param crashContext Contextual information about the crash and environment. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.h index f65ac0b4f..06bd4b44a 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.h @@ -31,13 +31,13 @@ #ifndef HDR_BSG_KSCrashState_h #define HDR_BSG_KSCrashState_h +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include -#include - typedef struct { // Saved data diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m index 2c91cc76b..266593139 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m @@ -239,11 +239,10 @@ + (NSString *)CPUArchForCPUType:(cpu_type_t)cpuType } + (NSString *)currentCPUArch { - NSString *result = - [self CPUArchForCPUType:bsg_kssysctl_int32ForName("hw.cputype") - subType:bsg_kssysctl_int32ForName("hw.cpusubtype")]; - - return result ?: [NSString stringWithUTF8String:bsg_ksmachcurrentCPUArch()]; + int32_t cpu_type = bsg_kssysctl_int32ForName("hw.cputype"); + int32_t cpu_subtype = bsg_kssysctl_int32ForName("hw.cpusubtype"); + NSString *result = [self CPUArchForCPUType:cpu_type subType:cpu_subtype]; + return result ?: [NSString stringWithFormat:@"unknown (type %d, subtype %d)", cpu_type, cpu_subtype]; } // ============================================================================ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h index 830f1beb7..f89d0a2c8 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h @@ -30,10 +30,6 @@ #ifndef HDR_BSG_KSCrashSentry_h #define HDR_BSG_KSCrashSentry_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_KSArchSpecific.h" #include "BSG_KSCrashType.h" @@ -42,6 +38,10 @@ extern "C" { #include #include +#ifdef __cplusplus +extern "C" { +#endif + // Some structures must be pre-allocated, so we must set an upper limit. // Note: Memory usage = 16 bytes per thread, pre-allocated once. #define MAX_CAPTURED_THREADS 1000 diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.h index b1b007094..8c4bc7b7b 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.h @@ -25,12 +25,12 @@ #ifndef HDR_BSG_KSCrashSentry_CPPException_h #define HDR_BSG_KSCrashSentry_CPPException_h +#include "BSG_KSCrashSentry.h" + #ifdef __cplusplus extern "C" { #endif -#include "BSG_KSCrashSentry.h" - /** Install the C++ exception handler. * * @param context Contextual information for the crash handler. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.h index c933412cf..059be9bc9 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.h @@ -30,18 +30,18 @@ #ifndef HDR_BSG_KSCrashSentry_MachException_h #define HDR_BSG_KSCrashSentry_MachException_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSGDefines.h" -#if BSG_HAVE_MACH_EXCEPTIONS - #include "BSG_KSCrashSentry.h" #include #include +#if BSG_HAVE_MACH_EXCEPTIONS + +#ifdef __cplusplus +extern "C" { +#endif + /** Install our custom mach exception handler. * * @param context Contextual information for the crash handler. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.h index 956930485..247d0660a 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.h @@ -30,12 +30,12 @@ #ifndef HDR_BSG_KSCrashSentry_NSException_h #define HDR_BSG_KSCrashSentry_NSException_h +#include "BSG_KSCrashSentry.h" + #ifdef __cplusplus extern "C" { #endif -#include "BSG_KSCrashSentry.h" - /** Install our custom NSException handler. * * @param context The crash context to fill out when a crash occurs. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Private.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Private.h index d1c3dfbd9..136ac388f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Private.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Private.h @@ -27,13 +27,13 @@ #ifndef HDR_BSG_KSCrashSentry_Private_h #define HDR_BSG_KSCrashSentry_Private_h +#include "BSG_KSCrashSentry.h" +#include "BSGDefines.h" + #ifdef __cplusplus extern "C" { #endif -#include "BSG_KSCrashSentry.h" -#include "BSGDefines.h" - #if BSG_HAVE_MACH_THREADS /** Suspend all non-reserved threads. * diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.h index 39f72d898..a42e2b6e9 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.h @@ -30,16 +30,16 @@ #ifndef HDR_BSG_KSCrashSentry_Signal_h #define HDR_BSG_KSCrashSentry_Signal_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSGDefines.h" #if BSG_HAVE_SIGNAL #include "BSG_KSCrashSentry.h" +#ifdef __cplusplus +extern "C" { +#endif + /** Install our custom signal handler. * * @param context The crash context to fill out when a crash occurs. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSArchSpecific.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSArchSpecific.h index 7b9d3a89a..ca0cf292f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSArchSpecific.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSArchSpecific.h @@ -30,10 +30,6 @@ #ifndef HDR_BSG_KSArchSpecific_h #define HDR_BSG_KSArchSpecific_h -#ifdef __cplusplus -extern "C" { -#endif - #include #ifdef __arm64__ @@ -42,8 +38,4 @@ extern "C" { #define BSG_STRUCT_MCONTEXT_L _STRUCT_MCONTEXT #endif -#ifdef __cplusplus -} -#endif - #endif // HDR_KSArchSpecific_h diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.h index e9b169d9c..dec94f2e0 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.h @@ -30,16 +30,16 @@ #ifndef HDR_BSG_KSBacktrace_h #define HDR_BSG_KSBacktrace_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_Symbolicate.h" #include "BSGDefines.h" #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** * Remove any pointer tagging from an instruction address * diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace_Private.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace_Private.h index 5f83ae3e3..650fd73fd 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace_Private.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace_Private.h @@ -27,16 +27,16 @@ #ifndef HDR_BSG_KSBacktrace_private_h #define HDR_BSG_KSBacktrace_private_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_KSArchSpecific.h" #include "BSG_KSBacktrace.h" #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Point at which bsg_ksbt_backtraceLength() will give up trying to count. * * This really only comes into play during a stack overflow. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashStringConversion.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashStringConversion.h index 9c14994c3..91e051571 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashStringConversion.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashStringConversion.h @@ -9,14 +9,13 @@ #ifndef BSG_KSCrashStringConversion_h #define BSG_KSCrashStringConversion_h +#include +#include + #ifdef __cplusplus extern "C" { #endif - -#include -#include - /** * Convert an unsigned integer to a string. * This will write a maximum of 21 characters (including the NUL) to dst. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h index 7ef0910a7..fa58fde0b 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h @@ -30,14 +30,14 @@ #ifndef HDR_BSG_KSFileUtils_h #define HDR_BSG_KSFileUtils_h -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Get the last entry in a file path. Assumes UNIX style separators. * * @param path The file path. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.h index a7d10ffb1..b55f656b3 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.h @@ -30,13 +30,13 @@ #ifndef HDR_BSG_KSJSONCodec_h #define HDR_BSG_KSJSONCodec_h +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include -#include - /* Tells the encoder to automatically determine the length of a field value. * Currently, this is done using strlen(). */ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h index 6d9b076e6..d0273d531 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h @@ -27,14 +27,14 @@ #ifndef HDR_BSG_KSLogger_h #define HDR_BSG_KSLogger_h -#ifdef __cplusplus -extern "C" { -#endif - #include #include "BugsnagLogger.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * Enables low-level logging. * diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c index d593948b0..b0535d991 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c @@ -43,11 +43,6 @@ #pragma mark - General Information - // ============================================================================ -const char *bsg_ksmachcurrentCPUArch(void) { - const NXArchInfo *archInfo = NXGetLocalArchInfo(); - return archInfo == NULL ? NULL : archInfo->name; -} - #define RETURN_NAME_FOR_ENUM(A) \ case A: \ return #A diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h index 902c87c63..f856c5194 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h @@ -30,10 +30,6 @@ #ifndef HDR_BSG_KSMach_h #define HDR_BSG_KSMach_h -#ifdef __cplusplus -extern "C" { -#endif - #include "BSG_KSArchSpecific.h" #include "BSGDefines.h" @@ -42,16 +38,14 @@ extern "C" { #include #include +#ifdef __cplusplus +extern "C" { +#endif + // ============================================================================ #pragma mark - General Information - // ============================================================================ -/** Get the current CPU architecture. - * - * @return The current architecture. - */ -const char *bsg_ksmachcurrentCPUArch(void); - /** Get the name of a mach exception. * * @param exceptionType The exception type. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachApple.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachApple.h index 0a1a0f98f..0ac5936c0 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachApple.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachApple.h @@ -19,14 +19,14 @@ #ifndef HDR_BSG_KSMachApple_h #define HDR_BSG_KSMachApple_h -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include +#ifdef __cplusplus +extern "C" { +#endif + // Avoid name clashes when copying structs from private headers #define pthread_t internal_pthread_t #define dispatch_queue_s internal_dispatch_queue_s diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSignalInfo.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSignalInfo.h index ca32e9947..bf7b97db8 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSignalInfo.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSignalInfo.h @@ -30,12 +30,12 @@ #ifndef HDR_BSG_KSSignalInfo_h #define HDR_BSG_KSSignalInfo_h +#include + #ifdef __cplusplus extern "C" { #endif -#include - /** Get the name of a signal. * * @param signal The signal. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h index 86b4c206b..b12e31afa 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h @@ -30,15 +30,15 @@ #ifndef HDR_BSG_KSSysCtl_h #define HDR_BSG_KSSysCtl_h -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Get an int32 value via sysctl by name. * * @param name The name of the command. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_Symbolicate.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_Symbolicate.h index 2cd3bc53b..590e71aa8 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_Symbolicate.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_Symbolicate.h @@ -8,12 +8,12 @@ #ifndef BSG_Symbolicate_h #define BSG_Symbolicate_h +#include + #ifdef __cplusplus extern "C" { #endif -#include - struct bsg_symbolicate_result { struct bsg_mach_image *image; uintptr_t function_address; diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index 4c888aafa..4be649983 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.27.2"; + _version = @"6.27.3"; _url = @"https://github.com/bugsnag/bugsnag-cocoa"; _dependencies = @[]; } diff --git a/Bugsnag/Payload/BugsnagUser.m b/Bugsnag/Payload/BugsnagUser.m index da65734db..fa26575d2 100644 --- a/Bugsnag/Payload/BugsnagUser.m +++ b/Bugsnag/Payload/BugsnagUser.m @@ -16,9 +16,19 @@ @implementation BugsnagUser - (instancetype)initWithDictionary:(NSDictionary *)dict { if ((self = [super init])) { + id nsnull = [NSNull null]; _id = dict[@"id"]; + if (_id == nsnull) { + _id = nil; + } _email = dict[@"email"]; + if (_email == nsnull) { + _email = nil; + } _name = dict[@"name"]; + if (_name == nsnull) { + _name = nil; + } } return self; } @@ -32,6 +42,14 @@ - (instancetype)initWithId:(NSString *)id name:(NSString *)name emailAddress:(NS return self; } +- (NSDictionary *)toJsonWithNSNulls { + NSMutableDictionary *dict = [NSMutableDictionary new]; + dict[@"id"] = self.id ?: [NSNull null]; + dict[@"email"] = self.email ?: [NSNull null]; + dict[@"name"] = self.name ?: [NSNull null]; + return [NSDictionary dictionaryWithDictionary:dict]; +} + - (NSDictionary *)toJson { NSMutableDictionary *dict = [NSMutableDictionary new]; dict[@"id"] = self.id; @@ -40,6 +58,7 @@ - (NSDictionary *)toJson { return [NSDictionary dictionaryWithDictionary:dict]; } + - (BugsnagUser *)withId { if (self.id) { return self; diff --git a/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h b/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h index 610eb20f1..f3a9cbd59 100644 --- a/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h +++ b/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h @@ -31,13 +31,13 @@ #ifndef HDR_BSG_KSCrashReportWriter_h #define HDR_BSG_KSCrashReportWriter_h +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include -#include - /** * Encapsulates report writing functionality. */ diff --git a/BugsnagNetworkRequestPlugin.podspec.json b/BugsnagNetworkRequestPlugin.podspec.json index fd7e80dce..9b50b097e 100644 --- a/BugsnagNetworkRequestPlugin.podspec.json +++ b/BugsnagNetworkRequestPlugin.podspec.json @@ -1,16 +1,16 @@ { "name": "BugsnagNetworkRequestPlugin", - "version": "6.27.2", + "version": "6.27.3", "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.27.2/BugsnagNetworkRequestPlugin/README.md", + "readme": "https://raw.githubusercontent.com/bugsnag/bugsnag-cocoa/v6.27.3/BugsnagNetworkRequestPlugin/README.md", "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.27.2" + "tag": "v6.27.3" }, "dependencies": { "Bugsnag": "~> 6.13" diff --git a/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPlugin.xcodeproj/project.pbxproj b/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPlugin.xcodeproj/project.pbxproj index 1110195f5..fff8a89fe 100644 --- a/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPlugin.xcodeproj/project.pbxproj +++ b/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPlugin.xcodeproj/project.pbxproj @@ -888,6 +888,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 372ZUL2ZB7; INFOPLIST_FILE = "../Tests/TestHost-iOS/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -905,6 +906,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 372ZUL2ZB7; INFOPLIST_FILE = "../Tests/TestHost-iOS/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1250,6 +1252,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = BugsnagNetworkRequestPlugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1273,6 +1276,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = BugsnagNetworkRequestPlugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1293,6 +1297,7 @@ GCC_WARN_PEDANTIC = NO; GCC_WARN_UNUSED_PARAMETER = NO; INFOPLIST_FILE = BugsnagNetworkRequestPluginTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1313,6 +1318,7 @@ GCC_WARN_PEDANTIC = NO; GCC_WARN_UNUSED_PARAMETER = NO; INFOPLIST_FILE = BugsnagNetworkRequestPluginTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPluginTests/BugsnagNetworkRequestPluginTests.m b/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPluginTests/BugsnagNetworkRequestPluginTests.m index f3ce61d3c..0e11b7ffc 100644 --- a/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPluginTests/BugsnagNetworkRequestPluginTests.m +++ b/BugsnagNetworkRequestPlugin/BugsnagNetworkRequestPluginTests/BugsnagNetworkRequestPluginTests.m @@ -87,6 +87,7 @@ - (void)resetBreadcrumbs { } - (void)setUp { + [super setUp]; [BSGURLSessionTracingDelegate setClient:(id)self]; [self resetBreadcrumbs]; } diff --git a/CHANGELOG.md b/CHANGELOG.md index 01df119da..63c0f7ee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ Changelog ========= +## 6.27.3 (2023-11-15) + +### Bug fixes + +* Remove include directives from inside of extern "C" sections because newer Xcode versions have issues with it + [1608](https://github.com/bugsnag/bugsnag-cocoa/pull/1608) + +* Setting user fields to nil will now clear them fully. + [1599](https://github.com/bugsnag/bugsnag-cocoa/pull/1599) + +* Crash fix: Detect and handle when WatchOS is running as an app rather than an extension. + [1588](https://github.com/bugsnag/bugsnag-cocoa/pull/1588) + +* Removed deprecated NXArchInfo code that was causing build issues. + [1584](https://github.com/bugsnag/bugsnag-cocoa/pull/1584) + +* Removed deprecated syscall on macos that was causing build issues. + [1577](https://github.com/bugsnag/bugsnag-cocoa/pull/1577) + +* Check app version to avoid detecting an app upgrade as an OOM + [1597](https://github.com/bugsnag/bugsnag-cocoa/pull/1597) + ## 6.27.2 (2023-07-24) ### Enhancements diff --git a/Framework/Info.plist b/Framework/Info.plist index e4125c7b5..b022480f9 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.27.2 + 6.27.3 CFBundleVersion 1 diff --git a/Gemfile b/Gemfile index 427043d09..95566ec28 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ gem 'cocoapods' # A reference to Maze Runner is only needed for running tests locally and if committed it must be # portable for CI, e.g. a specific release. However, leaving it commented out would mean quicker CI. -gem 'bugsnag-maze-runner', '~> 8.0' +gem 'bugsnag-maze-runner', '~> 8.8' # Use a specific branch #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'master' diff --git a/Gemfile.lock b/Gemfile.lock index 1c00ea98a..d50a61457 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,9 +21,9 @@ GEM faye-websocket (~> 0.11.0) selenium-webdriver (~> 4.2, < 4.6) atomos (0.1.3) - bugsnag (6.25.2) + bugsnag (6.26.0) concurrent-ruby (~> 1.0) - bugsnag-maze-runner (8.1.4) + bugsnag-maze-runner (8.8.0) appium_lib (~> 12.0.0) appium_lib_core (~> 5.4.0) bugsnag (~> 6.24) @@ -122,7 +122,7 @@ GEM ethon (0.16.0) ffi (>= 1.15.0) eventmachine (1.2.7) - faye-websocket (0.11.2) + faye-websocket (0.11.3) eventmachine (>= 0.12.0) websocket-driver (>= 0.5.1) ffi (1.15.5) @@ -140,25 +140,25 @@ GEM regexp_parser (~> 2.0) simpleidn (~> 0.2) uri_template (~> 0.7) - mime-types (3.4.1) + mime-types (3.5.1) mime-types-data (~> 3.2015) - mime-types-data (3.2023.0218.1) + mime-types-data (3.2023.1003) minitest (5.18.1) molinillo (0.8.0) multi_test (0.1.2) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) - nokogiri (1.15.3-x86_64-darwin) + nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) optimist (3.0.1) os (1.0.1) power_assert (2.0.3) public_suffix (4.0.7) racc (1.7.1) - rack (2.2.7) + rack (2.2.8) rake (12.3.3) - regexp_parser (2.8.1) + regexp_parser (2.8.2) rexml (3.2.5) ruby-macho (2.5.1) rubyzip (2.3.2) @@ -183,8 +183,8 @@ GEM unf_ext (0.0.8.2) uri_template (0.7.0) webrick (1.7.0) - websocket (1.2.9) - websocket-driver (0.7.5) + websocket (1.2.10) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xcodeproj (1.22.0) @@ -198,9 +198,10 @@ GEM PLATFORMS x86_64-darwin-19 x86_64-darwin-20 + x86_64-darwin-21 DEPENDENCIES - bugsnag-maze-runner (~> 8.0) + bugsnag-maze-runner (~> 8.8) cocoapods BUNDLED WITH diff --git a/Makefile b/Makefile index 990110d37..352c5ea02 100644 --- a/Makefile +++ b/Makefile @@ -30,12 +30,18 @@ else else ifeq ($(PLATFORM),iOS) SDK?=iphonesimulator - DEVICE?=iPhone 8 + ifeq ($(shell expr $(OS) \>= 17.0), 1) + DEVICE?=iPhone 14 + else + DEVICE?=iPhone 8 + endif + DESTINATION?=platform=iOS Simulator,name=$(DEVICE),OS=$(OS) RELEASE_DIR=Release-iphoneos else - SDK?=watchsimulator8.5 - DEVICE?=Apple Watch Series 5 - 40mm + SDK?=watchsimulator +# Due to the inconsistency of device names as a result of running; xcodebuild -downloadAllPlatforms, this dynamically selects the watchOS device. + DEVICE?=$(shell xcrun simctl list --json | jq -r '.devices."com.apple.CoreSimulator.SimRuntime.watchOS-8-5"[] | select(.name | test("Apple Watch Series 5 .+ ?40mm ?")) | .name') DESTINATION?=platform=watchOS Simulator,name=$(DEVICE),OS=$(OS) RELEASE_DIR=Release-watchos endif diff --git a/Tests/BugsnagTests/BSGAppKitTests.m b/Tests/BugsnagTests/BSGAppKitTests.m index c11002925..565d7bac8 100644 --- a/Tests/BugsnagTests/BSGAppKitTests.m +++ b/Tests/BugsnagTests/BSGAppKitTests.m @@ -6,9 +6,9 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" -@interface BSGAppKitTests : XCTestCase +@interface BSGAppKitTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGClientObserverTests.m b/Tests/BugsnagTests/BSGClientObserverTests.m index 32f165b9c..a9a60f846 100644 --- a/Tests/BugsnagTests/BSGClientObserverTests.m +++ b/Tests/BugsnagTests/BSGClientObserverTests.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "Bugsnag.h" #import "BugsnagClient+Private.h" @@ -15,7 +15,7 @@ #import "BugsnagMetadata+Private.h" #import "BugsnagUser+Private.h" -@interface BSGClientObserverTests : XCTestCase +@interface BSGClientObserverTests : BSGTestCase @property BugsnagClient *client; @property BSGClientObserverEvent event; @property id value; @@ -24,6 +24,7 @@ @interface BSGClientObserverTests : XCTestCase @implementation BSGClientObserverTests - (void)setUp { + [super setUp]; BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; self.client = [Bugsnag startWithConfiguration:config]; diff --git a/Tests/BugsnagTests/BSGConfigurationBuilderTests.m b/Tests/BugsnagTests/BSGConfigurationBuilderTests.m index 0aa05ce2c..682c79c32 100644 --- a/Tests/BugsnagTests/BSGConfigurationBuilderTests.m +++ b/Tests/BugsnagTests/BSGConfigurationBuilderTests.m @@ -1,4 +1,4 @@ -#import +#import "BSGTestCase.h" #import #import "BSGConfigurationBuilder.h" @@ -6,7 +6,7 @@ #import "BugsnagTestConstants.h" #import -@interface BSGConfigurationBuilderTests : XCTestCase +@interface BSGConfigurationBuilderTests : BSGTestCase @end @implementation BSGConfigurationBuilderTests diff --git a/Tests/BugsnagTests/BSGConnectivityTest.m b/Tests/BugsnagTests/BSGConnectivityTest.m index 75f18f5f2..7eefe6563 100644 --- a/Tests/BugsnagTests/BSGConnectivityTest.m +++ b/Tests/BugsnagTests/BSGConnectivityTest.m @@ -1,9 +1,9 @@ -#import +#import "BSGTestCase.h" #import "BSGConnectivity.h" #import "BSGDefines.h" -@interface BSGConnectivityTest : XCTestCase +@interface BSGConnectivityTest : BSGTestCase @end @implementation BSGConnectivityTest diff --git a/Tests/BugsnagTests/BSGDefinesTests.m b/Tests/BugsnagTests/BSGDefinesTests.m index e68b13b38..dc5154542 100644 --- a/Tests/BugsnagTests/BSGDefinesTests.m +++ b/Tests/BugsnagTests/BSGDefinesTests.m @@ -6,11 +6,11 @@ // Copyright © 2022 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGDefines.h" -@interface BSGDefinesTests : XCTestCase +@interface BSGDefinesTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGEventUploadKSCrashReportOperationTests.m b/Tests/BugsnagTests/BSGEventUploadKSCrashReportOperationTests.m index 86a3bf28d..3874b8e99 100644 --- a/Tests/BugsnagTests/BSGEventUploadKSCrashReportOperationTests.m +++ b/Tests/BugsnagTests/BSGEventUploadKSCrashReportOperationTests.m @@ -6,13 +6,14 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // +#import "BSGTestCase.h" + #import -#import #import "BSGEventUploadKSCrashReportOperation.h" #import "BSGInternalErrorReporter.h" -@interface BSGEventUploadKSCrashReportOperationTests : XCTestCase +@interface BSGEventUploadKSCrashReportOperationTests : BSGTestCase @property NSString *errorClass; @property NSString *context; diff --git a/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m b/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m index 8144687d6..296f8cfd5 100644 --- a/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m +++ b/Tests/BugsnagTests/BSGFeatureFlagStoreTests.m @@ -6,11 +6,11 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // -#import "BSGFeatureFlagStore.h" +#import "BSGTestCase.h" -#import +#import "BSGFeatureFlagStore.h" -@interface BSGFeatureFlagStoreTests : XCTestCase +@interface BSGFeatureFlagStoreTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGInternalErrorReporterTests.m b/Tests/BugsnagTests/BSGInternalErrorReporterTests.m index 37aeea86e..a9f75b620 100644 --- a/Tests/BugsnagTests/BSGInternalErrorReporterTests.m +++ b/Tests/BugsnagTests/BSGInternalErrorReporterTests.m @@ -6,7 +6,7 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import @@ -18,7 +18,7 @@ #import "BugsnagNotifier.h" #import "BSGPersistentDeviceID.h" -@interface BSGInternalErrorReporterTests : XCTestCase +@interface BSGInternalErrorReporterTests : BSGTestCase @property (nonatomic) BugsnagConfiguration *configuration; @@ -27,6 +27,7 @@ @interface BSGInternalErrorReporterTests : XCTestCase @implementation BSGInternalErrorReporterTests - (void)setUp { + [super setUp]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull" [BSGInternalErrorReporter setSharedInstance:nil]; @@ -63,14 +64,17 @@ - (void)testEventWithException { NSException *exception = nil; @try { - NSLog(@"%@", @[][0]); + [[NSException exceptionWithName:NSRangeException + reason:@"Something is out of range" + userInfo:nil] raise]; } @catch (NSException *e) { exception = e; } BugsnagEvent *event = [reporter eventWithException:exception diagnostics:nil groupingHash:@"test"]; XCTAssertEqualObjects(event.errors[0].errorClass, @"NSRangeException"); - XCTAssertEqualObjects(event.errors[0].errorMessage, @"*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray"); + XCTAssertEqualObjects(event.errors[0].errorMessage, @"Something is out of range"); + XCTAssertEqualObjects(event.groupingHash, @"test"); XCTAssertEqualObjects(event.threads, @[]); XCTAssertGreaterThan(event.errors[0].stacktrace.count, 0); diff --git a/Tests/BugsnagTests/BSGJSONSerializationTests.m b/Tests/BugsnagTests/BSGJSONSerializationTests.m index 531768040..2f37482e2 100644 --- a/Tests/BugsnagTests/BSGJSONSerializationTests.m +++ b/Tests/BugsnagTests/BSGJSONSerializationTests.m @@ -6,11 +6,11 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGJSONSerialization.h" -@interface BSGJSONSerializationTests : XCTestCase +@interface BSGJSONSerializationTests : BSGTestCase @end @implementation BSGJSONSerializationTests diff --git a/Tests/BugsnagTests/BSGNetworkBreadcrumbTests.m b/Tests/BugsnagTests/BSGNetworkBreadcrumbTests.m index e488e03e7..d52968b5d 100644 --- a/Tests/BugsnagTests/BSGNetworkBreadcrumbTests.m +++ b/Tests/BugsnagTests/BSGNetworkBreadcrumbTests.m @@ -5,11 +5,11 @@ // Created by Nick Dowell on 22/09/2021. // -#import "BSGNetworkBreadcrumb.h" +#import "BSGTestCase.h" -#import +#import "BSGNetworkBreadcrumb.h" -@interface BSGNetworkBreadcrumbTests : XCTestCase +@interface BSGNetworkBreadcrumbTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGNotificationBreadcrumbsTests.m b/Tests/BugsnagTests/BSGNotificationBreadcrumbsTests.m index efef0cf7c..98a3614b5 100644 --- a/Tests/BugsnagTests/BSGNotificationBreadcrumbsTests.m +++ b/Tests/BugsnagTests/BSGNotificationBreadcrumbsTests.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import @@ -19,7 +19,7 @@ #endif -@interface BSGNotificationBreadcrumbsTests : XCTestCase +@interface BSGNotificationBreadcrumbsTests : BSGTestCase @property NSNotificationCenter *notificationCenter; @property id notificationObject; @@ -114,6 +114,7 @@ @implementation BSGNotificationBreadcrumbsTests #pragma mark Setup - (void)setUp { + [super setUp]; self.breadcrumb = nil; BugsnagConfiguration *configuration = [[BugsnagConfiguration alloc] initWithApiKey:@"0192837465afbecd0192837465afbecd"]; self.notificationBreadcrumbs = [[BSGNotificationBreadcrumbs alloc] initWithConfiguration:configuration breadcrumbSink:self]; diff --git a/Tests/BugsnagTests/BSGOutOfMemoryTests.m b/Tests/BugsnagTests/BSGOutOfMemoryTests.m index aeda8869e..ca53178ba 100644 --- a/Tests/BugsnagTests/BSGOutOfMemoryTests.m +++ b/Tests/BugsnagTests/BSGOutOfMemoryTests.m @@ -1,4 +1,4 @@ -#import +#import "BSGTestCase.h" #import "BSGFileLocations.h" #import "BSGRunContext.h" @@ -10,7 +10,7 @@ #import "BugsnagSystemState.h" #import "BugsnagTestConstants.h" -@interface BSGOutOfMemoryTests : XCTestCase +@interface BSGOutOfMemoryTests : BSGTestCase @end @implementation BSGOutOfMemoryTests @@ -133,6 +133,9 @@ - (void)testLastLaunchTerminatedUnexpectedly { XCTAssertFalse(BSGRunContextWasKilled()); uuid_copy(lastRunContext.machoUUID, bsg_runContext->machoUUID); + strncpy(lastRunContext.bundleVersion, "999.99", sizeof(lastRunContext.bundleVersion)); + XCTAssertFalse(BSGRunContextWasKilled()); + lastRunContext.bootTime = 0; XCTAssertFalse(BSGRunContextWasKilled()); lastRunContext.bootTime = bsg_runContext->bootTime; diff --git a/Tests/BugsnagTests/BSGRunContextTests.m b/Tests/BugsnagTests/BSGRunContextTests.m index 0fb7ee656..beda07936 100644 --- a/Tests/BugsnagTests/BSGRunContextTests.m +++ b/Tests/BugsnagTests/BSGRunContextTests.m @@ -6,18 +6,19 @@ // Copyright © 2022 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGFileLocations.h" #import "BSGRunContext.h" -@interface BSGRunContextTests : XCTestCase +@interface BSGRunContextTests : BSGTestCase @end @implementation BSGRunContextTests - (void)setUp { + [super setUp]; if (!bsg_runContext) { BSGRunContextInit(BSGFileLocations.current.runContext); } diff --git a/Tests/BugsnagTests/BSGSerializationTests.m b/Tests/BugsnagTests/BSGSerializationTests.m index c36621781..1b5dce9ed 100644 --- a/Tests/BugsnagTests/BSGSerializationTests.m +++ b/Tests/BugsnagTests/BSGSerializationTests.m @@ -6,11 +6,11 @@ // Copyright © 2022 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGSerialization.h" -@interface BSGSerializationTests : XCTestCase +@interface BSGSerializationTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGStorageMigratorV0V1Tests.m b/Tests/BugsnagTests/BSGStorageMigratorV0V1Tests.m index 1c928d61c..f4e857a8d 100644 --- a/Tests/BugsnagTests/BSGStorageMigratorV0V1Tests.m +++ b/Tests/BugsnagTests/BSGStorageMigratorV0V1Tests.m @@ -6,13 +6,14 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" + #import "BSGStorageMigratorV0V1.h" #import "BugsnagClient+Private.h" #import "BugsnagConfiguration+Private.h" #import "BugsnagTestConstants.h" -@interface BSGStorageMigratorV0V1Tests : XCTestCase +@interface BSGStorageMigratorV0V1Tests : BSGTestCase @end @@ -79,6 +80,7 @@ - (NSDictionary *)getFiles { } - (void)setUp { + [super setUp]; NSFileManager *fm = [NSFileManager defaultManager]; NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *cachesPath = [self getCachesDir]; diff --git a/Tests/BugsnagTests/BSGTelemetryTests.m b/Tests/BugsnagTests/BSGTelemetryTests.m index 264cdecc5..889697bd6 100644 --- a/Tests/BugsnagTests/BSGTelemetryTests.m +++ b/Tests/BugsnagTests/BSGTelemetryTests.m @@ -6,14 +6,14 @@ // Copyright © 2022 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import #import "BSGTelemetry.h" #import "BugsnagTestConstants.h" -@interface BSGTelemetryTests : XCTestCase +@interface BSGTelemetryTests : BSGTestCase @end diff --git a/Tests/BugsnagTests/BSGTestCase.h b/Tests/BugsnagTests/BSGTestCase.h new file mode 100644 index 000000000..1986a7fe4 --- /dev/null +++ b/Tests/BugsnagTests/BSGTestCase.h @@ -0,0 +1,17 @@ +// +// BSGTestCase.h +// Bugsnag +// +// Created by Karl Stenerud on 10.11.23. +// Copyright © 2023 Bugsnag Inc. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface BSGTestCase : XCTestCase + +@end + +NS_ASSUME_NONNULL_END diff --git a/Tests/BugsnagTests/BSGTestCase.mm b/Tests/BugsnagTests/BSGTestCase.mm new file mode 100644 index 000000000..91008a43d --- /dev/null +++ b/Tests/BugsnagTests/BSGTestCase.mm @@ -0,0 +1,91 @@ +// +// BSGTestCase.m +// Bugsnag +// +// Created by Karl Stenerud on 10.11.23. +// Copyright © 2023 Bugsnag Inc. All rights reserved. +// + +#import "BSGTestCase.h" +#import "Swizzle.h" +#import + +using namespace bugsnag; + +@interface BSGWatchKitBundle: NSProxy + +@property(nonatomic,readwrite) NSBundle *bundle; +@property(nonatomic,readwrite) NSDictionary *dict; + +- (instancetype) initWithBundle:(NSBundle *)bundle; + +@end + +@implementation BSGWatchKitBundle + +- (instancetype) initWithBundle:(NSBundle *)bundle { + // Force the main bundle's dictionary to have an NSExtension section on WatchOS. + // This is necessary because the unit tests run in an extension environment but + // don't set this field that is normally present in a real environment, which + // confuses our extension detection code in + // Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m + NSMutableDictionary *dict = [NSBundle.mainBundle.infoDictionary mutableCopy]; + if (dict[@"NSExtension"] == nil) { + dict[@"NSExtension"] = @{ + @"NSExtensionAttributes": @{ + @"WKAppBundleIdentifier": @"com.bugsnag.swift-watchos.watchkitapp", + }, + @"NSExtensionPointIdentifier": @"com.apple.watchkit", + }; + } + _dict = dict; + _bundle = bundle; + + return self; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + if (self.bundle) { + [invocation setTarget:self.bundle]; + [invocation invoke]; + } +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel +{ + if ([self.bundle methodSignatureForSelector:sel]) { + return [self.bundle methodSignatureForSelector:sel]; + } else { + return [super methodSignatureForSelector:sel]; + } +} + +- (NSDictionary *)infoDictionary { + return self.dict; +} + +@end + + +@implementation BSGTestCase + +- (void)setUp { + if ([super respondsToSelector:@selector(setUp)]) { + [super setUp]; + } + +#if TARGET_OS_WATCH + static _Atomic(bool) hasSwizzled = false; + bool expectedValue = false; + if (atomic_compare_exchange_strong(&hasSwizzled, &expectedValue, true)) { + BSGWatchKitBundle *bundleProxy = [[BSGWatchKitBundle alloc] initWithBundle:NSBundle.mainBundle]; + ObjCSwizzle::setClassMethodImplementation(NSBundle.class, @selector(mainBundle), ^NSBundle *{ + return (NSBundle *)bundleProxy; + }); + } + +#endif +} + +@end diff --git a/Tests/BugsnagTests/BSGUtilsTests.m b/Tests/BugsnagTests/BSGUtilsTests.m index 70e9d9853..d87da8441 100644 --- a/Tests/BugsnagTests/BSGUtilsTests.m +++ b/Tests/BugsnagTests/BSGUtilsTests.m @@ -6,11 +6,11 @@ // Copyright © 2021 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGUtils.h" -@interface BSGUtilsTests : XCTestCase +@interface BSGUtilsTests : BSGTestCase @end @implementation BSGUtilsTests diff --git a/Tests/BugsnagTests/BugsnagApiClientTest.m b/Tests/BugsnagTests/BugsnagApiClientTest.m index 4abfb2992..dcdfdf391 100644 --- a/Tests/BugsnagTests/BugsnagApiClientTest.m +++ b/Tests/BugsnagTests/BugsnagApiClientTest.m @@ -6,13 +6,14 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" + #import "BugsnagApiClient.h" #import #import "BugsnagTestConstants.h" #import "URLSessionMock.h" -@interface BugsnagApiClientTest : XCTestCase +@interface BugsnagApiClientTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagApiValidationTest.m b/Tests/BugsnagTests/BugsnagApiValidationTest.m index b204e0c48..0d3dd7a3c 100644 --- a/Tests/BugsnagTests/BugsnagApiValidationTest.m +++ b/Tests/BugsnagTests/BugsnagApiValidationTest.m @@ -6,7 +6,8 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" + #import #import "BugsnagTestConstants.h" #import "TestSupport.h" @@ -14,13 +15,14 @@ /** * Validates that the Bugsnag API interface handles any invalid input gracefully. */ -@interface BugsnagApiValidationTest : XCTestCase +@interface BugsnagApiValidationTest : BSGTestCase @end @implementation BugsnagApiValidationTest - (void)setUp { + [super setUp]; [TestSupport purgePersistentData]; [Bugsnag startWithApiKey:DUMMY_APIKEY_32CHAR_1]; } diff --git a/Tests/BugsnagTests/BugsnagAppTest.m b/Tests/BugsnagTests/BugsnagAppTest.m index 94f1a19a7..092c85bdf 100644 --- a/Tests/BugsnagTests/BugsnagAppTest.m +++ b/Tests/BugsnagTests/BugsnagAppTest.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSG_KSSystemInfo.h" #import "BugsnagApp+Private.h" @@ -16,7 +16,7 @@ #include -@interface BugsnagAppTest : XCTestCase +@interface BugsnagAppTest : BSGTestCase @property NSDictionary *data; @property BugsnagConfiguration *config; @property NSString *codeBundleId; diff --git a/Tests/BugsnagTests/BugsnagBreadcrumbsTest.m b/Tests/BugsnagTests/BugsnagBreadcrumbsTest.m index 465269d06..26edd15d2 100644 --- a/Tests/BugsnagTests/BugsnagBreadcrumbsTest.m +++ b/Tests/BugsnagTests/BugsnagBreadcrumbsTest.m @@ -6,6 +6,8 @@ // // +#import "BSGTestCase.h" + #import "BSGUtils.h" #import "BSG_KSJSONCodec.h" #import "Bugsnag.h" @@ -15,7 +17,6 @@ #import "BugsnagTestConstants.h" #import "BSGDefines.h" -#import #import #import #import @@ -61,7 +62,7 @@ static id JSONObject(void (^ block)(BSG_KSCrashReportWriter *writer)) { }); } -@interface BugsnagBreadcrumbsTest : XCTestCase +@interface BugsnagBreadcrumbsTest : BSGTestCase @property(nonatomic, strong) BugsnagBreadcrumbs *crumbs; @end diff --git a/Tests/BugsnagTests/BugsnagClientMirrorTest.m b/Tests/BugsnagTests/BugsnagClientMirrorTest.m index e31ff1a27..3a5d9acb9 100644 --- a/Tests/BugsnagTests/BugsnagClientMirrorTest.m +++ b/Tests/BugsnagTests/BugsnagClientMirrorTest.m @@ -6,11 +6,12 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" + #import #import -@interface BugsnagClientMirrorTest : XCTestCase +@interface BugsnagClientMirrorTest : BSGTestCase @property NSSet *clientMethodsNotRequiredOnBugsnag; @property NSSet *bugsnagMethodsNotRequiredOnClient; @end @@ -26,6 +27,7 @@ @interface BugsnagClientMirrorTest : XCTestCase @implementation BugsnagClientMirrorTest - (void)setUp { + [super setUp]; // the following methods are implemented on BugsnagClient but do not need to // be mirrored on the Bugsnag facade self.clientMethodsNotRequiredOnBugsnag = [NSSet setWithArray:@[ diff --git a/Tests/BugsnagTests/BugsnagClientPayloadInfoTest.m b/Tests/BugsnagTests/BugsnagClientPayloadInfoTest.m index 31cca1552..fe60f3a31 100755 --- a/Tests/BugsnagTests/BugsnagClientPayloadInfoTest.m +++ b/Tests/BugsnagTests/BugsnagClientPayloadInfoTest.m @@ -6,20 +6,21 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagAppWithState+Private.h" #import "BugsnagConfiguration.h" #import "BugsnagDeviceWithState+Private.h" #import "BugsnagTestConstants.h" -@interface BugsnagClientPayloadInfoTest : XCTestCase +@interface BugsnagClientPayloadInfoTest : BSGTestCase @end @implementation BugsnagClientPayloadInfoTest - (void)setUp { + [super setUp]; BugsnagConfiguration *configuration = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; [Bugsnag startWithConfiguration:configuration]; } diff --git a/Tests/BugsnagTests/BugsnagClientTests.m b/Tests/BugsnagTests/BugsnagClientTests.m index 0efbb186c..4dde42d3e 100644 --- a/Tests/BugsnagTests/BugsnagClientTests.m +++ b/Tests/BugsnagTests/BugsnagClientTests.m @@ -6,6 +6,8 @@ // Copyright © 2020 Bugsnag. All rights reserved. // +#import "BSGTestCase.h" + #import "BSGInternalErrorReporter.h" #import "BSGKeys.h" #import "BSGRunContext.h" @@ -19,7 +21,6 @@ #import "BugsnagUser.h" #import -#import /** * Tests for BugsnagClient. @@ -31,7 +32,7 @@ * * For these reasons, test cases should only be added here as a matter of last resort. */ -@interface BugsnagClientTests : XCTestCase +@interface BugsnagClientTests : BSGTestCase @end NSString *BSGFormatSeverity(BSGSeverity severity); diff --git a/Tests/BugsnagTests/BugsnagCollectionsTests.m b/Tests/BugsnagTests/BugsnagCollectionsTests.m index b376fb0cd..3d816573f 100644 --- a/Tests/BugsnagTests/BugsnagCollectionsTests.m +++ b/Tests/BugsnagTests/BugsnagCollectionsTests.m @@ -6,10 +6,11 @@ // Copyright © 2019 Bugsnag. All rights reserved. // -@import XCTest; +#import "BSGTestCase.h" + #import "BugsnagCollections.h" -@interface BugsnagCollectionsTests : XCTestCase +@interface BugsnagCollectionsTests : BSGTestCase @end @interface BugsnagCollectionsTests_DummyObject : NSObject diff --git a/Tests/BugsnagTests/BugsnagConfigurationTests.m b/Tests/BugsnagTests/BugsnagConfigurationTests.m index bbff7fe76..b21702bc9 100644 --- a/Tests/BugsnagTests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagTests/BugsnagConfigurationTests.m @@ -2,7 +2,7 @@ * Unit test the BugsnagConfiguration class */ -#import +#import "BSGTestCase.h" #import "BugsnagConfiguration+Private.h" @@ -19,7 +19,7 @@ // MARK: - Tests // ============================================================================= -@interface BugsnagConfigurationTests : XCTestCase +@interface BugsnagConfigurationTests : BSGTestCase @end @implementation BugsnagConfigurationTests diff --git a/Tests/BugsnagTests/BugsnagDeviceTest.m b/Tests/BugsnagTests/BugsnagDeviceTest.m index d66039f94..f0bfd6e5e 100644 --- a/Tests/BugsnagTests/BugsnagDeviceTest.m +++ b/Tests/BugsnagTests/BugsnagDeviceTest.m @@ -6,13 +6,13 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSG_KSSystemInfo.h" #import "BugsnagDevice+Private.h" #import "BugsnagDeviceWithState+Private.h" -@interface BugsnagDeviceTest : XCTestCase +@interface BugsnagDeviceTest : BSGTestCase @property NSDictionary *data; @end diff --git a/Tests/BugsnagTests/BugsnagEnabledBreadcrumbTest.m b/Tests/BugsnagTests/BugsnagEnabledBreadcrumbTest.m index 06f33e8b9..7af6a20b9 100644 --- a/Tests/BugsnagTests/BugsnagEnabledBreadcrumbTest.m +++ b/Tests/BugsnagTests/BugsnagEnabledBreadcrumbTest.m @@ -6,12 +6,12 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagConfiguration+Private.h" #import "BugsnagTestConstants.h" -@interface BugsnagEnabledBreadcrumbTest : XCTestCase +@interface BugsnagEnabledBreadcrumbTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagErrorTest.m b/Tests/BugsnagTests/BugsnagErrorTest.m index 1662f9685..8838cf3cc 100644 --- a/Tests/BugsnagTests/BugsnagErrorTest.m +++ b/Tests/BugsnagTests/BugsnagErrorTest.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSGKeys.h" #import "BugsnagError+Private.h" @@ -17,13 +17,14 @@ NSString *BSGParseErrorMessage(NSDictionary *report, NSDictionary *error, NSString *errorType); -@interface BugsnagErrorTest : XCTestCase +@interface BugsnagErrorTest : BSGTestCase @property NSDictionary *event; @end @implementation BugsnagErrorTest - (void)setUp { + [super setUp]; NSDictionary *thread = @{ @"current_thread": @YES, @"crashed": @YES, diff --git a/Tests/BugsnagTests/BugsnagEventFromKSCrashReportTest.m b/Tests/BugsnagTests/BugsnagEventFromKSCrashReportTest.m index eb89ec446..b704af6d2 100644 --- a/Tests/BugsnagTests/BugsnagEventFromKSCrashReportTest.m +++ b/Tests/BugsnagTests/BugsnagEventFromKSCrashReportTest.m @@ -6,12 +6,12 @@ // Copyright © 2019 Bugsnag. All rights reserved. // -@import XCTest; +#import "BSGTestCase.h" #import "Bugsnag+Private.h" #import "BugsnagEvent+Private.h" -@interface BugsnagEventFromKSCrashReportTest : XCTestCase +@interface BugsnagEventFromKSCrashReportTest : BSGTestCase @property BugsnagEvent *event; @end diff --git a/Tests/BugsnagTests/BugsnagEventPersistLoadTest.m b/Tests/BugsnagTests/BugsnagEventPersistLoadTest.m index ad199cca8..10d9ef103 100644 --- a/Tests/BugsnagTests/BugsnagEventPersistLoadTest.m +++ b/Tests/BugsnagTests/BugsnagEventPersistLoadTest.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagEvent+Private.h" #import "BugsnagAppWithState.h" @@ -22,7 +22,7 @@ #import "BugsnagStackframe.h" #import "BugsnagThread.h" -@interface BugsnagEventPersistLoadTest : XCTestCase +@interface BugsnagEventPersistLoadTest : BSGTestCase @property NSDictionary *eventData; @end diff --git a/Tests/BugsnagTests/BugsnagEventTests.m b/Tests/BugsnagTests/BugsnagEventTests.m index 7766508fd..a1d06753f 100644 --- a/Tests/BugsnagTests/BugsnagEventTests.m +++ b/Tests/BugsnagTests/BugsnagEventTests.m @@ -6,8 +6,7 @@ // // -#import -#import +#import "BSGTestCase.h" #import "BSG_RFC3339DateTool.h" #import "Bugsnag.h" @@ -22,7 +21,7 @@ #import "BugsnagTestConstants.h" #import "BugsnagTestsDummyClass.h" -@interface BugsnagEventTests : XCTestCase +@interface BugsnagEventTests : BSGTestCase @end @implementation BugsnagEventTests diff --git a/Tests/BugsnagTests/BugsnagHandledStateTest.m b/Tests/BugsnagTests/BugsnagHandledStateTest.m index 0a35ea49c..cf47d6e47 100644 --- a/Tests/BugsnagTests/BugsnagHandledStateTest.m +++ b/Tests/BugsnagTests/BugsnagHandledStateTest.m @@ -6,11 +6,12 @@ // Copyright © 2017 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" + #import #import "BugsnagHandledState.h" -@interface BugsnagHandledStateTest : XCTestCase +@interface BugsnagHandledStateTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagMetadataRedactionTest.m b/Tests/BugsnagTests/BugsnagMetadataRedactionTest.m index c0be86955..5b9ce8dbe 100644 --- a/Tests/BugsnagTests/BugsnagMetadataRedactionTest.m +++ b/Tests/BugsnagTests/BugsnagMetadataRedactionTest.m @@ -6,12 +6,12 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagBreadcrumb+Private.h" #import "BugsnagEvent+Private.h" -@interface BugsnagMetadataRedactionTest : XCTestCase +@interface BugsnagMetadataRedactionTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagMetadataTests.m b/Tests/BugsnagTests/BugsnagMetadataTests.m index 24a121b9a..42b7677ca 100644 --- a/Tests/BugsnagTests/BugsnagMetadataTests.m +++ b/Tests/BugsnagTests/BugsnagMetadataTests.m @@ -6,17 +6,18 @@ // Copyright © 2020 Bugsnag. All rights reserved. // +#import "BSGTestCase.h" + #import "BugsnagMetadata.h" #import "BugsnagMetadata+Private.h" #import "BSGDefines.h" -#import #import #import // MARK: - Expose tested-class internals -@interface BugsnagMetadataTests : XCTestCase +@interface BugsnagMetadataTests : BSGTestCase @property BOOL delegateCalled; @property BugsnagMetadata *metadata; @end @@ -45,6 +46,7 @@ @implementation BugsnagMetadataTests @synthesize metadata; -(void) setUp { + [super setUp]; metadata = [[BugsnagMetadata alloc] init]; __weak __typeof__(self) weakSelf = self; diff --git a/Tests/BugsnagTests/BugsnagNotifierTest.m b/Tests/BugsnagTests/BugsnagNotifierTest.m index a89435ce1..e5dbe6c03 100644 --- a/Tests/BugsnagTests/BugsnagNotifierTest.m +++ b/Tests/BugsnagTests/BugsnagNotifierTest.m @@ -6,16 +6,18 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" + #import "BugsnagNotifier.h" -@interface BugsnagNotifierTest : XCTestCase +@interface BugsnagNotifierTest : BSGTestCase @property BugsnagNotifier *notifier; @end @implementation BugsnagNotifierTest - (void)setUp { + [super setUp]; self.notifier = [BugsnagNotifier new]; self.notifier.name = @"Foo Notifier"; self.notifier.version = @"6.0.0"; diff --git a/Tests/BugsnagTests/BugsnagOnBreadcrumbTest.m b/Tests/BugsnagTests/BugsnagOnBreadcrumbTest.m index 877d9a2e0..f73d6b765 100644 --- a/Tests/BugsnagTests/BugsnagOnBreadcrumbTest.m +++ b/Tests/BugsnagTests/BugsnagOnBreadcrumbTest.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "Bugsnag.h" #import "BugsnagBreadcrumb+Private.h" @@ -15,7 +15,7 @@ #import "BugsnagTestConstants.h" #import "BugsnagBreadcrumbs.h" -@interface BugsnagOnBreadcrumbTest : XCTestCase +@interface BugsnagOnBreadcrumbTest : BSGTestCase @end @implementation BugsnagOnBreadcrumbTest diff --git a/Tests/BugsnagTests/BugsnagOnCrashTest.m b/Tests/BugsnagTests/BugsnagOnCrashTest.m index 7dd48d8bb..31bdaf35e 100644 --- a/Tests/BugsnagTests/BugsnagOnCrashTest.m +++ b/Tests/BugsnagTests/BugsnagOnCrashTest.m @@ -6,12 +6,12 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import #import "BugsnagEvent+Private.h" -@interface BugsnagOnCrashTest : XCTestCase +@interface BugsnagOnCrashTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagPluginTest.m b/Tests/BugsnagTests/BugsnagPluginTest.m index 3a1393bec..06c89ae51 100644 --- a/Tests/BugsnagTests/BugsnagPluginTest.m +++ b/Tests/BugsnagTests/BugsnagPluginTest.m @@ -6,14 +6,14 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagTestConstants.h" #import "Bugsnag.h" #import "BugsnagClient+Private.h" #import "BugsnagConfiguration+Private.h" -@interface BugsnagPluginTest : XCTestCase +@interface BugsnagPluginTest : BSGTestCase @end diff --git a/Tests/BugsnagTests/BugsnagSessionTest.m b/Tests/BugsnagTests/BugsnagSessionTest.m index a2c48040e..cf4600d63 100644 --- a/Tests/BugsnagTests/BugsnagSessionTest.m +++ b/Tests/BugsnagTests/BugsnagSessionTest.m @@ -6,7 +6,7 @@ // Copyright © 2017 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagApp+Private.h" #import "BugsnagConfiguration+Private.h" @@ -16,7 +16,7 @@ #import "BSG_RFC3339DateTool.h" #import "BugsnagTestConstants.h" -@interface BugsnagSessionTest : XCTestCase +@interface BugsnagSessionTest : BSGTestCase @property BugsnagApp *app; @property BugsnagDevice *device; @property NSDictionary *serializedSession; @@ -25,6 +25,7 @@ @interface BugsnagSessionTest : XCTestCase @implementation BugsnagSessionTest - (void)setUp { + [super setUp]; self.app = [self generateApp]; self.device = [self generateDevice]; self.serializedSession = [self generateSerializedSession]; diff --git a/Tests/BugsnagTests/BugsnagSessionTrackerStopTest.m b/Tests/BugsnagTests/BugsnagSessionTrackerStopTest.m index 7e1628330..53416fcc7 100644 --- a/Tests/BugsnagTests/BugsnagSessionTrackerStopTest.m +++ b/Tests/BugsnagTests/BugsnagSessionTrackerStopTest.m @@ -6,13 +6,13 @@ // Copyright © 2019 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagSession+Private.h" #import "BugsnagSessionTracker.h" #import "BugsnagTestConstants.h" -@interface BugsnagSessionTrackerStopTest : XCTestCase +@interface BugsnagSessionTrackerStopTest : BSGTestCase @property BugsnagConfiguration *configuration; @property BugsnagSessionTracker *tracker; @end diff --git a/Tests/BugsnagTests/BugsnagSessionTrackerTest.m b/Tests/BugsnagTests/BugsnagSessionTrackerTest.m index 016464429..13bf85853 100644 --- a/Tests/BugsnagTests/BugsnagSessionTrackerTest.m +++ b/Tests/BugsnagTests/BugsnagSessionTrackerTest.m @@ -6,7 +6,7 @@ // Copyright © 2017 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagUser.h" #import "BugsnagConfiguration+Private.h" @@ -16,7 +16,7 @@ #import "BSGDefines.h" #import "BSGWatchKit.h" -@interface BugsnagSessionTrackerTest : XCTestCase +@interface BugsnagSessionTrackerTest : BSGTestCase @property BugsnagConfiguration *configuration; @property BugsnagSessionTracker *sessionTracker; @property BugsnagUser *user; diff --git a/Tests/BugsnagTests/BugsnagStackframeTest.m b/Tests/BugsnagTests/BugsnagStackframeTest.m index c647c2385..d8333fb7d 100644 --- a/Tests/BugsnagTests/BugsnagStackframeTest.m +++ b/Tests/BugsnagTests/BugsnagStackframeTest.m @@ -6,12 +6,12 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSG_KSMachHeaders.h" #import "BugsnagStackframe+Private.h" -@interface BugsnagStackframeTest : XCTestCase +@interface BugsnagStackframeTest : BSGTestCase @property NSDictionary *frameDict; @property NSArray *binaryImages; @end @@ -19,6 +19,7 @@ @interface BugsnagStackframeTest : XCTestCase @implementation BugsnagStackframeTest - (void)setUp { + [super setUp]; self.frameDict = @{ @"symbol_addr": @0x10b574fa0, @"instruction_addr": @0x10b5756bf, @@ -253,6 +254,10 @@ - (void)testRealCallStackSymbols { // This frame is not in any known image return; } + if ([stackframe.method isEqualToString: @"start_sim"]) { + // This frame is part of the simulator environment + return; + } #endif XCTAssertNotNil(stackframe.machoUuid); XCTAssertNotNil(stackframe.machoVmAddress); diff --git a/Tests/BugsnagTests/BugsnagStacktraceTest.m b/Tests/BugsnagTests/BugsnagStacktraceTest.m index 123184ac8..e11e94611 100644 --- a/Tests/BugsnagTests/BugsnagStacktraceTest.m +++ b/Tests/BugsnagTests/BugsnagStacktraceTest.m @@ -6,11 +6,11 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagStacktrace.h" -@interface BugsnagStacktraceTest : XCTestCase +@interface BugsnagStacktraceTest : BSGTestCase @property NSDictionary *frameDict; @property NSArray *binaryImages; @end @@ -18,6 +18,7 @@ @interface BugsnagStacktraceTest : XCTestCase @implementation BugsnagStacktraceTest - (void)setUp { + [super setUp]; self.frameDict = @{ @"symbol_addr": @0x10b574fa0, @"instruction_addr": @0x10b5756bf, diff --git a/Tests/BugsnagTests/BugsnagSwiftConfigurationTests.swift b/Tests/BugsnagTests/BugsnagSwiftConfigurationTests.swift index b10f56e4f..fa648f29f 100644 --- a/Tests/BugsnagTests/BugsnagSwiftConfigurationTests.swift +++ b/Tests/BugsnagTests/BugsnagSwiftConfigurationTests.swift @@ -6,10 +6,9 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -import XCTest import Bugsnag -class BugsnagSwiftConfigurationTests: XCTestCase { +class BugsnagSwiftConfigurationTests: BSGTestCase { /** * Objective C trailing-NSError* initializers are translated into throwing diff --git a/Tests/BugsnagTests/BugsnagSwiftPublicAPITests.swift b/Tests/BugsnagTests/BugsnagSwiftPublicAPITests.swift index a5b53d9a5..5b4ec5211 100644 --- a/Tests/BugsnagTests/BugsnagSwiftPublicAPITests.swift +++ b/Tests/BugsnagTests/BugsnagSwiftPublicAPITests.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -import XCTest +import Bugsnag /** * Test all public APIs from Swift. Purely existence tests, no attempt to verify correctness @@ -34,7 +34,7 @@ class myMetadata: NSObject, BugsnagMetadataStore, BugsnagClassLevelMetadataStore func clearMetadata(section sectionName: String, key: String) {} } -class BugsnagSwiftPublicAPITests: XCTestCase { +class BugsnagSwiftPublicAPITests: BSGTestCase { let apiKey = "01234567890123456789012345678901" let ex = NSException(name: NSExceptionName("exception"), diff --git a/Tests/BugsnagTests/BugsnagSwiftTests.swift b/Tests/BugsnagTests/BugsnagSwiftTests.swift index a30eab783..2e0511c63 100644 --- a/Tests/BugsnagTests/BugsnagSwiftTests.swift +++ b/Tests/BugsnagTests/BugsnagSwiftTests.swift @@ -7,9 +7,9 @@ // // Swift unit tests of global Bugsnag behaviour -import XCTest +import Bugsnag -class BugsnagSwiftTests: XCTestCase { +class BugsnagSwiftTests: BSGTestCase { /** * Confirm that the addMetadata() method is exposed to Swift correctly diff --git a/Tests/BugsnagTests/BugsnagTests.m b/Tests/BugsnagTests/BugsnagTests.m index 268f76665..da803d83b 100644 --- a/Tests/BugsnagTests/BugsnagTests.m +++ b/Tests/BugsnagTests/BugsnagTests.m @@ -7,7 +7,7 @@ // // Unit tests of global Bugsnag behaviour -#import +#import "BSGTestCase.h" #import "Bugsnag.h" #import "BugsnagClient+Private.h" @@ -18,7 +18,7 @@ // MARK: - BugsnagTests -@interface BugsnagTests : XCTestCase +@interface BugsnagTests : BSGTestCase @end @implementation BugsnagTests diff --git a/Tests/BugsnagTests/BugsnagThreadSerializationTest.m b/Tests/BugsnagTests/BugsnagThreadSerializationTest.m index 0a41b0c29..98e41a76e 100644 --- a/Tests/BugsnagTests/BugsnagThreadSerializationTest.m +++ b/Tests/BugsnagTests/BugsnagThreadSerializationTest.m @@ -3,11 +3,11 @@ // Copyright (c) 2018 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagEvent+Private.h" -@interface BugsnagThreadSerializationTest : XCTestCase +@interface BugsnagThreadSerializationTest : BSGTestCase @end @implementation BugsnagThreadSerializationTest diff --git a/Tests/BugsnagTests/BugsnagThreadTests.m b/Tests/BugsnagTests/BugsnagThreadTests.m index 6f664aa1f..75d9305e2 100644 --- a/Tests/BugsnagTests/BugsnagThreadTests.m +++ b/Tests/BugsnagTests/BugsnagThreadTests.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BSG_KSMachHeaders.h" #import "BugsnagStackframe+Private.h" @@ -15,7 +15,7 @@ #import #import -@interface BugsnagThreadTests : XCTestCase +@interface BugsnagThreadTests : BSGTestCase @property NSArray *binaryImages; @property NSDictionary *thread; @end @@ -23,11 +23,13 @@ @interface BugsnagThreadTests : XCTestCase @implementation BugsnagThreadTests + (void)setUp { + [super setUp]; bsg_mach_headers_initialize(); bsg_mach_headers_get_images(); // Ensure call stack can be symbolicated } - (void)setUp { + [super setUp]; self.thread = @{ @"current_thread": @YES, @"crashed": @YES, diff --git a/Tests/BugsnagTests/BugsnagUserTest.m b/Tests/BugsnagTests/BugsnagUserTest.m index 3bf3e458a..b74779ed5 100644 --- a/Tests/BugsnagTests/BugsnagUserTest.m +++ b/Tests/BugsnagTests/BugsnagUserTest.m @@ -6,12 +6,12 @@ // Copyright © 2017 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" #import "BugsnagEvent+Private.h" #import "BugsnagUser+Private.h" -@interface BugsnagUserTest : XCTestCase +@interface BugsnagUserTest : BSGTestCase @end @implementation BugsnagUserTest @@ -31,6 +31,35 @@ - (void)testDictDeserialisation { XCTAssertEqualObjects(user.name, @"Tom Bombadil"); } +- (void)testDictNullDeserialisation { + + NSDictionary *dict = @{ + @"id": [NSNull null], + @"email": [NSNull null], + @"name": [NSNull null] + }; + BugsnagUser *user = [[BugsnagUser alloc] initWithDictionary:dict]; + + XCTAssertNotNil(user); + XCTAssertNil(user.id); + XCTAssertNil(user.email); + XCTAssertNil(user.name); +} + +- (void)testDictNullSerialisation { + BugsnagUser *user = [[BugsnagUser alloc] initWithId:nil name:nil emailAddress:nil]; + NSDictionary *dict = [user toJson]; + XCTAssertEqualObjects(@{}, dict); + + dict = [user toJsonWithNSNulls]; + NSDictionary *expected = @{ + @"id": [NSNull null], + @"email": [NSNull null], + @"name": [NSNull null] + }; + XCTAssertEqualObjects(expected, dict); +} + - (void)testPayloadSerialisation { BugsnagUser *payload = [[BugsnagUser alloc] initWithId:@"test" name:@"Tom Bombadil" emailAddress:@"fake@example.com"]; NSDictionary *rootNode = [payload toJson]; diff --git a/Tests/BugsnagTests/ClientApiValidationTest.m b/Tests/BugsnagTests/ClientApiValidationTest.m index 75a5c3bca..b24edd3ae 100644 --- a/Tests/BugsnagTests/ClientApiValidationTest.m +++ b/Tests/BugsnagTests/ClientApiValidationTest.m @@ -6,20 +6,22 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" + #import #import "BugsnagTestConstants.h" /** * Validates that the Client API interface handles any invalid input gracefully. */ -@interface ClientApiValidationTest : XCTestCase +@interface ClientApiValidationTest : BSGTestCase @property BugsnagClient *client; @end @implementation ClientApiValidationTest - (void)setUp { + [super setUp]; BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; [config addOnSendErrorBlock:^BOOL(BugsnagEvent *event) { return NO; diff --git a/Tests/BugsnagTests/ConfigurationApiValidationTest.m b/Tests/BugsnagTests/ConfigurationApiValidationTest.m index 2c4c0fb8b..3cb8a1101 100644 --- a/Tests/BugsnagTests/ConfigurationApiValidationTest.m +++ b/Tests/BugsnagTests/ConfigurationApiValidationTest.m @@ -6,7 +6,8 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" + #import #import "BugsnagConfiguration+Private.h" #import "BugsnagPlugin.h" @@ -23,13 +24,14 @@ - (void)unload {} /** * Validates that the Configuration API interface handles any invalid input gracefully. */ -@interface ConfigurationApiValidationTest : XCTestCase +@interface ConfigurationApiValidationTest : BSGTestCase @property BugsnagConfiguration *config; @end @implementation ConfigurationApiValidationTest - (void)setUp { + [super setUp]; self.config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; } diff --git a/Tests/BugsnagTests/EventApiValidationTest.m b/Tests/BugsnagTests/EventApiValidationTest.m index 164093a9a..5e964756f 100644 --- a/Tests/BugsnagTests/EventApiValidationTest.m +++ b/Tests/BugsnagTests/EventApiValidationTest.m @@ -6,7 +6,7 @@ // Copyright © 2020 Bugsnag Inc. All rights reserved. // -#import +#import "BSGTestCase.h" #import #import "BugsnagEvent+Private.h" @@ -14,13 +14,14 @@ /** * Validates that the Event API interface handles any invalid input gracefully. */ -@interface EventApiValidationTest : XCTestCase +@interface EventApiValidationTest : BSGTestCase @property BugsnagEvent *event; @end @implementation EventApiValidationTest - (void)setUp { + [super setUp]; self.event = [[BugsnagEvent alloc] initWithKSReport:@{@"user": @{}}]; } diff --git a/Tests/BugsnagTests/FileBasedTest.h b/Tests/BugsnagTests/FileBasedTest.h index 70e231638..270e78fd6 100644 --- a/Tests/BugsnagTests/FileBasedTest.h +++ b/Tests/BugsnagTests/FileBasedTest.h @@ -6,9 +6,9 @@ // Copyright © 2023 Bugsnag. All rights reserved. // -#import +#import "BSGTestCase.h" -@interface FileBasedTest : XCTestCase +@interface FileBasedTest : BSGTestCase @property(readwrite, nonatomic) NSString *filePath; diff --git a/Tests/BugsnagTests/FileBasedTest.m b/Tests/BugsnagTests/FileBasedTest.m index 219550380..849f11ab0 100644 --- a/Tests/BugsnagTests/FileBasedTest.m +++ b/Tests/BugsnagTests/FileBasedTest.m @@ -15,6 +15,7 @@ - (NSString *)newPath { } - (void)setUp { + [super setUp]; self.filePath = [self newPath]; } diff --git a/Tests/BugsnagTests/Info.plist b/Tests/BugsnagTests/Info.plist index 4e9769662..7d778be1a 100644 --- a/Tests/BugsnagTests/Info.plist +++ b/Tests/BugsnagTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.27.2 + 6.27.3 CFBundleVersion 1 diff --git a/Tests/BugsnagTests/Swizzle.h b/Tests/BugsnagTests/Swizzle.h new file mode 100644 index 000000000..68c22611f --- /dev/null +++ b/Tests/BugsnagTests/Swizzle.h @@ -0,0 +1,36 @@ +// +// Swizzle.h +// Bugsnag +// +// Created by Karl Stenerud on 21.04.23. +// Copyright © 2023 Bugsnag. All rights reserved. +// + +#pragma once + +#import + +namespace bugsnag { + +class ObjCSwizzle { +public: + /** + * Replace a class's current method implementation with a new implementation block, returning the replaced one. + * Returns nil if the method was not found (in the class or any superclass). + */ + static IMP _Nullable setClassMethodImplementation(Class _Nonnull clazz, SEL _Nonnull selector, id _Nonnull implementationBlock) noexcept; + + /** + * Replace a class's override of a method (i.e. only if this class overrides the method). No superclass implementation is replaced. + * Returns nil if no method was replaced (either method not found, or this class doesn't overrde the method). + */ + static IMP _Nullable replaceInstanceMethodOverride(Class _Nonnull cls, SEL _Nonnull name, id _Nonnull block) noexcept; + + /** + * Get any classes or superclasses that implement the specified selector. + */ + static NSArray * _Nonnull getClassesWithSelector(Class _Nullable cls, SEL _Nonnull selector) noexcept; + +}; + +} diff --git a/Tests/BugsnagTests/Swizzle.mm b/Tests/BugsnagTests/Swizzle.mm new file mode 100644 index 000000000..abc784471 --- /dev/null +++ b/Tests/BugsnagTests/Swizzle.mm @@ -0,0 +1,68 @@ +// +// Swizzle.mm +// Bugsnag +// +// Created by Karl Stenerud on 21.04.23. +// Copyright © 2023 Bugsnag. All rights reserved. +// + +#import "Swizzle.h" +#import + +namespace bugsnag { + +IMP ObjCSwizzle::setClassMethodImplementation(Class _Nonnull clazz, SEL selector, id _Nonnull implementationBlock) noexcept { + Method method = class_getClassMethod(clazz, selector); + if (method) { + return method_setImplementation(method, imp_implementationWithBlock(implementationBlock)); + } else { + NSLog(@"Could not set IMP for selector %s on class %@", sel_getName(selector), clazz); + return nil; + } +} + +IMP ObjCSwizzle::replaceInstanceMethodOverride(Class clazz, SEL selector, id block) noexcept { + Method method = nullptr; + + // Not using class_getInstanceMethod because we don't want to modify the + // superclass's implementation. + auto methodCount = 0U; + Method *methods = class_copyMethodList(clazz, &methodCount); + if (methods) { + for (auto i = 0U; i < methodCount; i++) { + if (sel_isEqual(method_getName(methods[i]), selector)) { + method = methods[i]; + break; + } + } + free(methods); + } + + if (!method) { + // This is not considered an error. + return nil; + } + + return method_setImplementation(method, imp_implementationWithBlock(block)); +} + +NSArray *ObjCSwizzle::getClassesWithSelector(Class cls, SEL selector) noexcept { + NSMutableArray *result = [NSMutableArray new]; + for (; class_getInstanceMethod(cls, selector); cls = [cls superclass]) { + if (!cls) { + break; + } + Class superCls = [cls superclass]; + Method classMethod = class_getInstanceMethod(cls, selector); + Method superMethod = class_getInstanceMethod(superCls, selector); + IMP classIMP = classMethod ? method_getImplementation(classMethod) : nil; + IMP superIMP = superMethod ? method_getImplementation(superMethod) : nil; + if (classIMP != superIMP) { + [result addObject:(Class _Nonnull)cls]; + } + } + return result; +}; + + +} diff --git a/Tests/BugsnagTests/Tests-Bridging-Header.h b/Tests/BugsnagTests/Tests-Bridging-Header.h index c54081022..3603229d8 100644 --- a/Tests/BugsnagTests/Tests-Bridging-Header.h +++ b/Tests/BugsnagTests/Tests-Bridging-Header.h @@ -5,3 +5,4 @@ #import #import "BugsnagTestConstants.h" +#import "BSGTestCase.h" diff --git a/Tests/KSCrashTests/BSG_KSFileTests.m b/Tests/KSCrashTests/BSG_KSFileTests.m index 622563519..f4ad55f71 100644 --- a/Tests/KSCrashTests/BSG_KSFileTests.m +++ b/Tests/KSCrashTests/BSG_KSFileTests.m @@ -20,6 +20,7 @@ @interface BSG_KSFileTests : XCTestCase @implementation BSG_KSFileTests - (void)setUp { + [super setUp]; self.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[self description]]; self.fileDescriptor = open(self.filePath.fileSystemRepresentation, O_RDWR | O_CREAT | O_EXCL, 0644); } diff --git a/Tests/KSCrashTests/BSG_KSMachHeadersTests.m b/Tests/KSCrashTests/BSG_KSMachHeadersTests.m index 3d5370417..a41c082bd 100644 --- a/Tests/KSCrashTests/BSG_KSMachHeadersTests.m +++ b/Tests/KSCrashTests/BSG_KSMachHeadersTests.m @@ -53,6 +53,7 @@ @interface BSG_KSMachHeadersTests : XCTestCase @implementation BSG_KSMachHeadersTests - (void)setUp { + [super setUp]; bsg_mach_headers_initialize(); } diff --git a/Tests/KSCrashTests/KSCrashNames_Test.m b/Tests/KSCrashTests/KSCrashNames_Test.m index 01f1f17f2..77947e9fc 100644 --- a/Tests/KSCrashTests/KSCrashNames_Test.m +++ b/Tests/KSCrashTests/KSCrashNames_Test.m @@ -16,14 +16,6 @@ @interface KSCrashNames_Test : XCTestCase @implementation KSCrashNames_Test -- (void)setUp { - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. -} - - (void)testValidStates { XCTAssertTrue(strcmp(bsg_kscrashthread_state_name(TH_STATE_RUNNING), "TH_STATE_RUNNING") == 0); XCTAssertTrue(strcmp(bsg_kscrashthread_state_name(TH_STATE_STOPPED), "TH_STATE_STOPPED") == 0); diff --git a/Tests/KSCrashTests/KSCrashSentry_Tests.m b/Tests/KSCrashTests/KSCrashSentry_Tests.m index c744d2370..4f6fa5365 100755 --- a/Tests/KSCrashTests/KSCrashSentry_Tests.m +++ b/Tests/KSCrashTests/KSCrashSentry_Tests.m @@ -44,6 +44,7 @@ @interface KSCrashSentry_Tests : XCTestCase @end @implementation KSCrashSentry_Tests - (void) setUp { + [super setUp]; bsg_kscrashsentry_installWithContext(&context, BSG_KSCrashTypeAll, onCrash); } diff --git a/Tests/KSCrashTests/KSCrashState_Tests.m b/Tests/KSCrashTests/KSCrashState_Tests.m index cf5e401f8..1c8dbe94b 100755 --- a/Tests/KSCrashTests/KSCrashState_Tests.m +++ b/Tests/KSCrashTests/KSCrashState_Tests.m @@ -38,11 +38,10 @@ @interface bsg_kscrashstate_Tests : FileBasedTestCase @implementation bsg_kscrashstate_Tests -#if TARGET_OS_OSX || TARGET_OS_TV // Not needed on iOS because there the tests are injected into a host app +#if TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH // Not needed on iOS because there the tests are injected into a host app - (void)setUp { - struct BSGRunContext *oldContext = bsg_runContext; static struct BSGRunContext context = {0}; context.isForeground = YES; // These tests assume applicationState == .active diff --git a/Tests/TestHost-iOS/Info.plist b/Tests/TestHost-iOS/Info.plist index 3037b6e45..28bed4d56 100644 --- a/Tests/TestHost-iOS/Info.plist +++ b/Tests/TestHost-iOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.27.2 + 6.27.3 CFBundleVersion 1 LSRequiresIPhoneOS diff --git a/VERSION b/VERSION index 5f64a2958..0fc326d66 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.27.2 +6.27.3 diff --git a/docker-compose.yml b/docker-compose.yml index 539321250..6ee1dc6b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,7 @@ x-common-environment: &common-environment BUILDKITE_BUILD_CREATOR: BUILDKITE_BUILD_NUMBER: BUILDKITE_BUILD_URL: + BUILDKITE_JOB_ID: BUILDKITE_LABEL: BUILDKITE_MESSAGE: BUILDKITE_PIPELINE_NAME: diff --git a/features/app_hangs.feature b/features/app_hangs.feature index 93966d9ee..8f31de417 100644 --- a/features/app_hangs.feature +++ b/features/app_hangs.feature @@ -107,7 +107,7 @@ Feature: App hangs Scenario: Fatal app hangs should be reported if appHangThresholdMillis = BugsnagAppHangThresholdFatalOnly When I run "AppHangFatalOnlyScenario" - And I wait for 3 seconds + And I wait for 6 seconds And I kill and relaunch the app And I set the HTTP status code to 500 And I configure Bugsnag for "AppHangFatalOnlyScenario" @@ -139,7 +139,7 @@ Feature: App hangs Scenario: Fatal app hangs should not be reported if enabledErrorTypes.appHangs = false When I run "AppHangFatalDisabledScenario" - And I wait for 3 seconds + And I wait for 5 seconds And I kill and relaunch the app And I configure Bugsnag for "AppHangFatalDisabledScenario" Then I should receive no errors @@ -147,7 +147,8 @@ Feature: App hangs @skip_macos Scenario: Fatal app hangs should be reported if the app hangs before going to the background When I run "AppHangFatalOnlyScenario" - And I send the app to the background for 3 seconds + And I wait for 5 seconds + And I send the app to the background And I kill and relaunch the app And I configure Bugsnag for "AppHangFatalOnlyScenario" And I wait to receive an error @@ -156,7 +157,7 @@ Feature: App hangs @skip_macos Scenario: Fatal app hangs should not be reported if they occur once the app is in the background When I run "AppHangDidEnterBackgroundScenario" - And I send the app to the background for 3 seconds + And I send the app to the background for 6 seconds And I kill and relaunch the app And I configure Bugsnag for "AppHangDidEnterBackgroundScenario" Then I should receive no errors @@ -182,7 +183,7 @@ Feature: App hangs @skip_macos Scenario: Background app hangs should be reported if reportBackgroundAppHangs = true When I run "ReportBackgroundAppHangScenario" - And I send the app to the background for 3 seconds + And I send the app to the background And I wait to receive an error Then the exception "errorClass" equals "App Hang" And the exception "message" equals "The app's main thread failed to respond to an event within 1000 milliseconds" diff --git a/features/barebone_tests.feature b/features/barebone_tests.feature index 497eea7c7..691eeb534 100644 --- a/features/barebone_tests.feature +++ b/features/barebone_tests.feature @@ -68,7 +68,7 @@ Feature: Barebone tests And the event "metaData.error.nsexception.userInfo.date" equals "2001-01-01 00:00:00 +0000" And the event "metaData.error.nsexception.userInfo.NSUnderlyingError" matches "Error Domain=ErrorDomain Code=0" And the event "metaData.error.nsexception.userInfo.scenario" equals "BareboneTestHandledScenario" - And the event "metaData.error.reason" equals "-[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]" + And the event "metaData.error.reason" equals "Something is out of range" And the event "metaData.error.type" equals "nsexception" And the event "metaData.usage" is null And the event "metaData.user.email" is null @@ -103,7 +103,7 @@ Feature: Barebone tests | notify | rangeException | And the event does not contain the feature flag "nope" And the exception "errorClass" equals "NSRangeException" - And the exception "message" equals "-[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]" + And the exception "message" equals "Something is out of range" And the exception "type" equals "cocoa" And the error payload field "events.0.app.dsymUUIDs" is a non-empty array And the error payload field "events.0.app.duration" is a number @@ -199,7 +199,7 @@ Feature: Barebone tests And the event "metaData.error.nsexception.userInfo.date" equals "2001-01-01 00:00:00 +0000" And the event "metaData.error.nsexception.userInfo.NSUnderlyingError" matches "Error Domain=ErrorDomain Code=0" And the event "metaData.error.nsexception.userInfo.scenario" equals "BareboneTestUnhandledErrorScenario" - And the event "metaData.error.reason" equals "*** -[__NSArray0 objectAtIndex:]: index 42 beyond bounds for empty NSArray" + And the event "metaData.error.reason" equals "Something is out of range" And the event "metaData.error.type" equals "nsexception" And the event "metaData.usage" is null And the event "metaData.user.email" is null @@ -227,7 +227,7 @@ Feature: Barebone tests | featureFlag | variant | | Testing | | And the exception "errorClass" equals "NSRangeException" - And the exception "message" equals "*** -[__NSArray0 objectAtIndex:]: index 42 beyond bounds for empty NSArray" + And the exception "message" equals "Something is out of range" And the exception "type" equals "cocoa" And the error payload field "events.0.app.dsymUUIDs" is a non-empty array And the error payload field "events.0.app.duration" is a number @@ -244,6 +244,7 @@ Feature: Barebone tests @skip_macos @skip_ios_16 # https://smartbear.atlassian.net/browse/PLAT-9724 + @skip_ios_17 Scenario: Barebone test: Out Of Memory When I run "OOMScenario" diff --git a/features/crashprobe.feature b/features/crashprobe.feature index e04fa68ab..7809025a9 100644 --- a/features/crashprobe.feature +++ b/features/crashprobe.feature @@ -54,7 +54,8 @@ Feature: Reporting crash events | | | ___forwarding___ | And the "method" of stack frame 4 equals "_CF_forwarding_prep_0" - And the "method" of stack frame 5 equals "-[NonExistentMethodScenario run]" + # Skipped pending PLAT-10759 + #And the "method" of stack frame 5 equals "-[NonExistentMethodScenario run]" And the "isPC" of stack frame 0 is null And the "isLR" of stack frame 0 is null diff --git a/features/delivery.feature b/features/delivery.feature index 6855ffa90..08af636e5 100644 --- a/features/delivery.feature +++ b/features/delivery.feature @@ -46,7 +46,7 @@ Feature: Delivery of errors And I configure Bugsnag for "OldHandledErrorScenario" And I wait to receive an error And I wait for the fixture to process the response - # The error should now have been deleted + # The error should now have been deleted And I kill and relaunch the app And I clear the error queue And I configure Bugsnag for "OldHandledErrorScenario" @@ -157,6 +157,7 @@ Feature: Delivery of errors And the event "usage.system.stringCharsTruncated" is not null And the event "usage.system.stringsTruncated" is not null + @skip_ios_17 Scenario Outline: Attempt Delivery On Crash When I set the app to "" mode And I run "AttemptDeliveryOnCrashScenario" @@ -174,7 +175,31 @@ Feature: Delivery of errors And I wait to receive 2 sessions Then I should receive no error Examples: - | scenario_mode | error_type | error_class | message | - | NSException | nsexception | NSRangeException | *** -[__NSArray0 objectAtIndex:]: index 42 beyond bounds for empty NSArray | - | SwiftFatalError | mach | Fatal error | Unexpectedly found nil while unwrapping an Optional value | - | BadAccess | mach | EXC_BAD_ACCESS | Attempted to dereference garbage pointer 0x20. | + | scenario_mode | error_type | error_class | message | + | NSException | nsexception | NSRangeException | Something is out of range | + | SwiftFatalError | mach | Fatal error | Unexpectedly found nil while unwrapping an Optional value | + | BadAccess | mach | EXC_BAD_ACCESS | Attempted to dereference garbage pointer 0x20. | + + @skip_below_ios_17 + @skip_macos + Scenario Outline: Attempt Delivery On Crash iOS 17 + When I set the app to "" mode + And I run "AttemptDeliveryOnCrashScenario" + And I wait to receive an error + Then the error is valid for the error reporting API + And the event "context" equals "OnSendError" + And the exception "errorClass" equals "" + And the exception "message" equals "" + And the event "metaData.error.type" equals "" + And the event "unhandled" is true + And the event "usage.config.attemptDeliveryOnCrash" is true + And I discard the oldest error + And I relaunch the app after a crash + And I configure Bugsnag for "AttemptDeliveryOnCrashScenario" + And I wait to receive 2 sessions + Then I should receive no error + Examples: + | scenario_mode | error_type | error_class | message | + | NSException | nsexception | NSRangeException | Something is out of range | + | SwiftFatalError | mach | Fatal error | Unexpectedly found nil while unwrapping an Optional value | + | BadAccess | mach | EXC_BAD_ACCESS | Attempted to dereference garbage pointer 0x20. | diff --git a/features/fixtures/ios/iOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/ios/iOSTestApp.xcodeproj/project.pbxproj index 4e06e3de9..af196dd77 100644 --- a/features/fixtures/ios/iOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/ios/iOSTestApp.xcodeproj/project.pbxproj @@ -86,6 +86,8 @@ 01F6B75E2832757F00B75C5D /* OversizedCrashReportScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F6B75C2832757F00B75C5D /* OversizedCrashReportScenario.swift */; }; 01F6B75F2832757F00B75C5D /* OversizedHandledErrorScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F6B75D2832757F00B75C5D /* OversizedHandledErrorScenario.swift */; }; 01FA9EC426D63BB20059FF4A /* AppHangInTerminationScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FA9EC326D63BB20059FF4A /* AppHangInTerminationScenario.swift */; }; + 095E095A2AF3BE8D00273F1F /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095E09592AF3BE8D00273F1F /* Logging.swift */; }; + 095E095D2AF3BFDA00273F1F /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E095C2AF3BFDA00273F1F /* Logging.m */; }; 6526A0D4248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6526A0D3248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift */; }; 8A096DF627C7E56C00DB6ECC /* CxxUnexpectedScenario.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8A096DF527C7E56C00DB6ECC /* CxxUnexpectedScenario.mm */; }; 8A096DFC27C7E77600DB6ECC /* CxxBareThrowScenario.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8A096DFB27C7E77600DB6ECC /* CxxBareThrowScenario.mm */; }; @@ -283,6 +285,9 @@ 01F6B75C2832757F00B75C5D /* OversizedCrashReportScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OversizedCrashReportScenario.swift; sourceTree = ""; }; 01F6B75D2832757F00B75C5D /* OversizedHandledErrorScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OversizedHandledErrorScenario.swift; sourceTree = ""; }; 01FA9EC326D63BB20059FF4A /* AppHangInTerminationScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppHangInTerminationScenario.swift; sourceTree = ""; }; + 095E09592AF3BE8D00273F1F /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; + 095E095B2AF3BFDA00273F1F /* Logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = ""; }; + 095E095C2AF3BFDA00273F1F /* Logging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Logging.m; sourceTree = ""; }; 6526A0D3248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadConfigFromFileAutoScenario.swift; sourceTree = ""; }; 8A096DF527C7E56C00DB6ECC /* CxxUnexpectedScenario.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CxxUnexpectedScenario.mm; sourceTree = ""; }; 8A096DFB27C7E77600DB6ECC /* CxxBareThrowScenario.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CxxBareThrowScenario.mm; sourceTree = ""; }; @@ -454,6 +459,7 @@ isa = PBXGroup; children = ( AA4C7F1429AEA0C4009B09A9 /* BugsnagWrapper.swift */, + 095E09592AF3BE8D00273F1F /* Logging.swift */, ); name = utils; path = ../shared/utils; @@ -547,10 +553,13 @@ 8AB1081823301FE600672818 /* HandledErrorValidReleaseStageScenario.swift */, F429526319377A8848136413 /* HandledExceptionScenario.swift */, 8AF8FCAD22BD23BA00A967CA /* HandledInternalNotifyScenario.swift */, + 967F6F1129B2236A0054EED8 /* InternalWorkingsScenario.swift */, 01847DD526453D4E00ADA4C7 /* InvalidCrashReportScenario.m */, 01B6BB7425D5748800FC4DE6 /* LastRunInfoScenario.swift */, 6526A0D3248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift */, 8AB65FCB22DC77CB001200AB /* LoadConfigFromFileScenario.swift */, + 095E095B2AF3BFDA00273F1F /* Logging.h */, + 095E095C2AF3BFDA00273F1F /* Logging.m */, E7B79CD1247FD66E0039FB88 /* ManualContextClientScenario.swift */, E7B79CCF247FD6660039FB88 /* ManualContextConfigurationScenario.swift */, E7B79CD3247FD6760039FB88 /* ManualContextOnErrorScenario.swift */, @@ -657,7 +666,6 @@ 010BAAF22833CE570003FF36 /* UserPersistencePersistUserClientScenario.m */, 010BAAF82833CE570003FF36 /* UserPersistencePersistUserScenario.m */, E700EE49247D1164008CFFB6 /* UserSessionOverrideScenario.swift */, - 967F6F1129B2236A0054EED8 /* InternalWorkingsScenario.swift */, ); name = scenarios; path = ../shared/scenarios; @@ -843,10 +851,12 @@ 010BAB0B2833CE570003FF36 /* CxxExceptionOverrideScenario.mm in Sources */, 01DE903826CE99B800455213 /* CriticalThermalStateScenario.swift in Sources */, 01B6BBB625DA82B800FC4DE6 /* SendLaunchCrashesSynchronouslyScenario.swift in Sources */, + 095E095D2AF3BFDA00273F1F /* Logging.m in Sources */, F4295836C8AF75547C675E8D /* ReleasedObjectScenario.m in Sources */, 01E5EAD225B713990066EA8A /* OOMScenario.m in Sources */, 010BAB3D2833D2890003FF36 /* DisabledReleaseStageManualSessionScenario.swift in Sources */, 01F6B75E2832757F00B75C5D /* OversizedCrashReportScenario.swift in Sources */, + 095E095A2AF3BE8D00273F1F /* Logging.swift in Sources */, 8A530CCC22FDDBF000F0C108 /* ManyConcurrentNotifyScenario.m in Sources */, 010BAB112833CEEC0003FF36 /* AppAndDeviceAttributesConfigOverrideScenario.swift in Sources */, 010BAB0A2833CE570003FF36 /* DisableSignalsExceptionScenario.m in Sources */, diff --git a/features/fixtures/ios/iOSTestApp/AppDelegate.swift b/features/fixtures/ios/iOSTestApp/AppDelegate.swift index 00612edbc..fa9713898 100644 --- a/features/fixtures/ios/iOSTestApp/AppDelegate.swift +++ b/features/fixtures/ios/iOSTestApp/AppDelegate.swift @@ -1,4 +1,5 @@ import UIKit +import os @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -6,6 +7,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + logInfo("========== Fixture app has launched ==========") return true } } diff --git a/features/fixtures/ios/iOSTestApp/CommandReaderThread.swift b/features/fixtures/ios/iOSTestApp/CommandReaderThread.swift index c410abb8f..85f5e2a8a 100644 --- a/features/fixtures/ios/iOSTestApp/CommandReaderThread.swift +++ b/features/fixtures/ios/iOSTestApp/CommandReaderThread.swift @@ -21,9 +21,19 @@ class CommandReaderThread: Thread { Scenario.baseMazeAddress = self.loadMazeRunnerAddress() } + var isRunningCommand = false + while true { - Scenario.executeMazeRunnerCommand() { scenarioName, eventMode in - self.action(scenarioName, eventMode) + if isRunningCommand { + logInfo("A command fetch is already in progress, waiting 1 second more...") + } else { + isRunningCommand = true + Scenario.executeMazeRunnerCommand() { scenarioName, eventMode in + if (!scenarioName.isEmpty) { + self.action(scenarioName, eventMode) + } + isRunningCommand = false + } } Thread.sleep(forTimeInterval: 1) } @@ -41,7 +51,7 @@ class CommandReaderThread: Thread { for n in 1...30 { let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] - log("Reading Maze Runner address from fixture_config.json") + logInfo("Reading Maze Runner address from fixture_config.json") do { let fileUrl = URL(fileURLWithPath: "fixture_config", relativeTo: documentsUrl).appendingPathExtension("json") @@ -49,28 +59,23 @@ class CommandReaderThread: Thread { let savedData = try Data(contentsOf: fileUrl) if let contents = String(data: savedData, encoding: .utf8) { - NSLog("Found fixture_config.json after %d seconds", n) + logInfo(String(format: "Found fixture_config.json after %d seconds", n)) let decoder = JSONDecoder() let jsonData = contents.data(using: .utf8) let config = try decoder.decode(FixtureConfig.self, from: jsonData!) let address = "http://" + config.maze_address - log("Using Maze Runner address: " + address) + logInfo("Using Maze Runner address: " + address) return address } } catch let error as NSError { - log("Failed to read fixture_config.json: \(error)") + logWarn("Failed to read fixture_config.json: \(error)") } - log("Waiting for fixture_config.json to appear") + logInfo("Waiting for fixture_config.json to appear") Thread.sleep(forTimeInterval: 1) } - log("Unable to read from fixture_config.json, defaulting to BrowserStack environment") + logError("Unable to read from fixture_config.json, defaulting to BrowserStack environment") return bsAddress; } } - -private func log(_ message: String) { - NSLog("%@", message) - kslog("\(Date()) \(message)") -} diff --git a/features/fixtures/ios/iOSTestApp/ViewController.swift b/features/fixtures/ios/iOSTestApp/ViewController.swift index 708d5306f..ab408a0da 100644 --- a/features/fixtures/ios/iOSTestApp/ViewController.swift +++ b/features/fixtures/ios/iOSTestApp/ViewController.swift @@ -25,6 +25,7 @@ class ViewController: UIViewController { self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))) NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) apiKeyField.text = UserDefaults.standard.string(forKey: "apiKey") + logInfo("Read API key from UserDefaults: \(apiKeyField.text!)") // Poll for commands to run if #available(iOS 10.0, *) { @@ -43,18 +44,18 @@ class ViewController: UIViewController { if Scenario.current == nil { prepareScenario() - log("Starting Bugsnag for scenario: \(Scenario.current!)") + logInfo("Starting Bugsnag for scenario: \(Scenario.current!)") Scenario.current!.startBugsnag() } - log("Running scenario: \(Scenario.current!)") + logInfo("Running scenario: \(Scenario.current!)") Scenario.current!.run() } @IBAction func startBugsnag() { prepareScenario() - log("Starting Bugsnag for scenario: \(Scenario.current!)") + logInfo("Starting Bugsnag for scenario: \(Scenario.current!)") Scenario.current!.startBugsnag() } @@ -67,7 +68,7 @@ class ViewController: UIViewController { if (apiKeyField.text!.count > 0) { // Manual testing mode - use the real dashboard and the API key provided let apiKey = apiKeyField.text! - NSLog("Running in manual mode with API key: %@", apiKey) + logInfo("Running in manual mode with API key: \(apiKey)") UserDefaults.standard.setValue(apiKey, forKey: "apiKey") config = BugsnagConfiguration(apiKeyField.text!) } @@ -81,8 +82,3 @@ class ViewController: UIViewController { Scenario.current?.didEnterBackgroundNotification() } } - -private func log(_ message: String) { - NSLog("%@", message) - kslog("\(Date()) \(message)") -} diff --git a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj index 86fcd1b83..4bba25555 100644 --- a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj @@ -182,6 +182,8 @@ 01F6B74F2832381300B75C5D /* OversizedCrashReportScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F6B74B2832381300B75C5D /* OversizedCrashReportScenario.swift */; }; 01F7365A278D90440000113C /* NetworkBreadcrumbsScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F73659278D90440000113C /* NetworkBreadcrumbsScenario.swift */; }; 01FA9EC626D64FFF0059FF4A /* AppHangInTerminationScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FA9EC526D64FFF0059FF4A /* AppHangInTerminationScenario.swift */; }; + 095E095F2AF3C98F00273F1F /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095E095E2AF3C98F00273F1F /* Logging.swift */; }; + 095E09622AF3C9A500273F1F /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E09612AF3C9A500273F1F /* Logging.m */; }; 8A096DF827C7E63A00DB6ECC /* CxxUnexpectedScenario.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8A096DF727C7E63A00DB6ECC /* CxxUnexpectedScenario.mm */; }; 8A096DFA27C7E6D800DB6ECC /* CxxBareThrowScenario.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8A096DF927C7E6D800DB6ECC /* CxxBareThrowScenario.mm */; }; 967F6F1629B767CE0054EED8 /* InternalWorkingsScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967F6F1529B767CE0054EED8 /* InternalWorkingsScenario.swift */; }; @@ -388,6 +390,9 @@ 01F6B74B2832381300B75C5D /* OversizedCrashReportScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OversizedCrashReportScenario.swift; sourceTree = ""; }; 01F73659278D90440000113C /* NetworkBreadcrumbsScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkBreadcrumbsScenario.swift; sourceTree = ""; }; 01FA9EC526D64FFF0059FF4A /* AppHangInTerminationScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppHangInTerminationScenario.swift; sourceTree = ""; }; + 095E095E2AF3C98F00273F1F /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; + 095E09602AF3C9A500273F1F /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = ""; }; + 095E09612AF3C9A500273F1F /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logging.m; sourceTree = ""; }; 2C49722B331FF4B0DC477462 /* Pods-macOSTestApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-macOSTestApp.release.xcconfig"; path = "Target Support Files/Pods-macOSTestApp/Pods-macOSTestApp.release.xcconfig"; sourceTree = ""; }; 5C65BFC9838298CFA8A35072 /* Pods_macOSTestApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_macOSTestApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8A096DF727C7E63A00DB6ECC /* CxxUnexpectedScenario.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CxxUnexpectedScenario.mm; sourceTree = ""; }; @@ -494,6 +499,8 @@ 01B6BB7125D56CBF00FC4DE6 /* LastRunInfoScenario.swift */, 01F47C23254B1B2C00B184AD /* LoadConfigFromFileAutoScenario.swift */, 01F47C94254B1B2F00B184AD /* LoadConfigFromFileScenario.swift */, + 095E09602AF3C9A500273F1F /* Logging.h */, + 095E09612AF3C9A500273F1F /* Logging.m */, 01F47C3B254B1B2D00B184AD /* ManualContextClientScenario.swift */, 01F47C47254B1B2D00B184AD /* ManualContextConfigurationScenario.swift */, 01F47C82254B1B2F00B184AD /* ManualContextOnErrorScenario.swift */, @@ -658,6 +665,7 @@ isa = PBXGroup; children = ( AA4C7F1729AEA31D009B09A9 /* BugsnagWrapper.swift */, + 095E095E2AF3C98F00273F1F /* Logging.swift */, ); name = utils; path = ../shared/utils; @@ -795,6 +803,7 @@ 01F47D08254B1B3100B184AD /* AutoSessionCustomVersionScenario.m in Sources */, 01F47CC6254B1B3100B184AD /* HandledExceptionScenario.swift in Sources */, 01F47D0D254B1B3100B184AD /* LoadConfigFromFileScenario.swift in Sources */, + 095E09622AF3C9A500273F1F /* Logging.m in Sources */, 01F47CF5254B1B3100B184AD /* StoppedSessionScenario.swift in Sources */, 010BAB772833D34A0003FF36 /* DiscardClassesHandledExceptionRegexScenario.swift in Sources */, 01F47D23254B1B3100B184AD /* SwiftAssertionScenario.swift in Sources */, @@ -849,6 +858,7 @@ 010BAB722833D34A0003FF36 /* BareboneTestHandledScenario.swift in Sources */, 017D9CFC2833C81100B0AA87 /* DisableMachExceptionScenario.m in Sources */, 01DE903A26CEAD1200455213 /* CriticalThermalStateScenario.swift in Sources */, + 095E095F2AF3C98F00273F1F /* Logging.swift in Sources */, 01F47CF9254B1B3100B184AD /* BreadcrumbCallbackDiscardScenario.swift in Sources */, AA6ACD1E2773E39C006464C4 /* UserInfoScenario.swift in Sources */, 01018BAB25E417EC000312C6 /* AsyncSafeMallocScenario.m in Sources */, diff --git a/features/fixtures/macos/macOSTestApp/MainWindowController.m b/features/fixtures/macos/macOSTestApp/MainWindowController.m index 479d24ee4..16fa42131 100644 --- a/features/fixtures/macos/macOSTestApp/MainWindowController.m +++ b/features/fixtures/macos/macOSTestApp/MainWindowController.m @@ -9,12 +9,10 @@ #import "MainWindowController.h" #import "Scenario.h" +#import "Logging.h" #import -static void BSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL; - - @interface MainWindowController () // These properties are used with Cocoa Bindings @@ -50,39 +48,39 @@ - (BugsnagConfiguration *)configuration { } - (IBAction)runScenario:(id)sender { - BSLog(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); + logDebug(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); // Cater for multiple calls to -run if (!Scenario.currentScenario) { [Scenario createScenarioNamed:self.scenarioName withConfig:[self configuration]]; Scenario.currentScenario.eventMode = self.scenarioMetadata; - BSLog(@"Starting Bugsnag for scenario: %@", Scenario.currentScenario); + logInfo(@"Starting Bugsnag for scenario: %@", Scenario.currentScenario); [Scenario.currentScenario startBugsnag]; } - BSLog(@"Will run scenario: %@", Scenario.currentScenario); + logInfo(@"Will run scenario: %@", Scenario.currentScenario); // Using dispatch_async to prevent AppleEvents swallowing exceptions. // For more info see https://www.chimehq.com/blog/sad-state-of-exceptions // 0.1s delay allows accessibility APIs to finish handling the mouse click and returns control to the tests framework. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - BSLog(@"Running scenario: %@", Scenario.currentScenario); + logInfo(@"Running scenario: %@", Scenario.currentScenario); [Scenario.currentScenario run]; }); } - (IBAction)startBugsnag:(id)sender { - BSLog(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); + logDebug(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); [Scenario createScenarioNamed:self.scenarioName withConfig:[self configuration]]; Scenario.currentScenario.eventMode = self.scenarioMetadata; - BSLog(@"Starting Bugsnag for scenario: %@", Scenario.currentScenario); + logInfo(@"Starting Bugsnag for scenario: %@", Scenario.currentScenario); [Scenario.currentScenario startBugsnag]; } - (IBAction)clearPersistentData:(id)sender { - BSLog(@"Clearing persistent data"); + logInfo(@"Clearing persistent data"); [Scenario clearPersistentData]; } @@ -100,13 +98,3 @@ - (IBAction)executeMazeRunnerCommand:(id)sender { } @end - - -static void BSLog(NSString *format, ...) { - va_list vl; - va_start(vl, format); - NSString *message = [[NSString alloc] initWithFormat:format arguments:vl]; - NSLog(@"%@", message); - kslog(message.UTF8String); - va_end(vl); -} diff --git a/features/fixtures/shared/scenarios/AbortOverrideScenario.m b/features/fixtures/shared/scenarios/AbortOverrideScenario.m index 9b8c33b3c..1f1e3d347 100644 --- a/features/fixtures/shared/scenarios/AbortOverrideScenario.m +++ b/features/fixtures/shared/scenarios/AbortOverrideScenario.m @@ -25,6 +25,7 @@ */ #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" @interface AbortOverrideScenario : MarkUnhandledHandledScenario @end diff --git a/features/fixtures/shared/scenarios/AbortScenario.m b/features/fixtures/shared/scenarios/AbortScenario.m index b1d5aa8d2..3c5a2d3e1 100644 --- a/features/fixtures/shared/scenarios/AbortScenario.m +++ b/features/fixtures/shared/scenarios/AbortScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" @interface AbortScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/AccessNonObjectScenario.m b/features/fixtures/shared/scenarios/AccessNonObjectScenario.m index f932f74a1..0927824ef 100644 --- a/features/fixtures/shared/scenarios/AccessNonObjectScenario.m +++ b/features/fixtures/shared/scenarios/AccessNonObjectScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" /** * Call NSLog(@"%@", 16);, causing a crash when the runtime attempts to treat 16 as a pointer to an object. diff --git a/features/fixtures/shared/scenarios/AppHangDefaultConfigScenario.swift b/features/fixtures/shared/scenarios/AppHangDefaultConfigScenario.swift index 7f57fff30..f6eb77f5a 100644 --- a/features/fixtures/shared/scenarios/AppHangDefaultConfigScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangDefaultConfigScenario.swift @@ -2,8 +2,8 @@ class AppHangDefaultConfigScenario: Scenario { override func run() { let timeInterval: TimeInterval = 5 - NSLog("Simulating an app hang of \(timeInterval) seconds...") + logDebug("Simulating an app hang of \(timeInterval) seconds...") Thread.sleep(forTimeInterval: timeInterval) - NSLog("Finished sleeping") + logDebug("Finished sleeping") } } diff --git a/features/fixtures/shared/scenarios/AppHangDidBecomeActiveScenario.swift b/features/fixtures/shared/scenarios/AppHangDidBecomeActiveScenario.swift index db796072e..b54f0781e 100644 --- a/features/fixtures/shared/scenarios/AppHangDidBecomeActiveScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangDidBecomeActiveScenario.swift @@ -10,7 +10,7 @@ class AppHangDidBecomeActiveScenario: Scenario { override func run() { NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { - NSLog("Received \($0.name), now sleeping for 3 seconds...") + logDebug("Received \($0.name), now sleeping for 3 seconds...") Thread.sleep(forTimeInterval: 3) } } diff --git a/features/fixtures/shared/scenarios/AppHangDidEnterBackgroundScenario.swift b/features/fixtures/shared/scenarios/AppHangDidEnterBackgroundScenario.swift index a5e650522..73eaeccf4 100644 --- a/features/fixtures/shared/scenarios/AppHangDidEnterBackgroundScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangDidEnterBackgroundScenario.swift @@ -4,7 +4,7 @@ class AppHangDidEnterBackgroundScenario: Scenario { override func run() { NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { - NSLog("Received \($0.name), now hanging indefinitely...") + logDebug("Received \($0.name), now hanging indefinitely...") while true {} } } diff --git a/features/fixtures/shared/scenarios/AppHangDisabledScenario.swift b/features/fixtures/shared/scenarios/AppHangDisabledScenario.swift index 2be4b4de3..513b2df18 100644 --- a/features/fixtures/shared/scenarios/AppHangDisabledScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangDisabledScenario.swift @@ -7,8 +7,8 @@ class AppHangDisabledScenario: Scenario { override func run() { let timeInterval: TimeInterval = 5 - NSLog("Simulating an app hang of \(timeInterval) seconds...") + logDebug("Simulating an app hang of \(timeInterval) seconds...") Thread.sleep(forTimeInterval: timeInterval) - NSLog("Finished sleeping") + logDebug("Finished sleeping") } } diff --git a/features/fixtures/shared/scenarios/AppHangFatalDisabledScenario.swift b/features/fixtures/shared/scenarios/AppHangFatalDisabledScenario.swift index 912674eb2..a5b08b688 100644 --- a/features/fixtures/shared/scenarios/AppHangFatalDisabledScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangFatalDisabledScenario.swift @@ -7,7 +7,7 @@ class AppHangFatalDisabledScenario: Scenario { } override func run() { - NSLog("Hanging indefinitely...") + logDebug("Hanging indefinitely...") // Use asyncAfter to allow the Appium click event to be handled DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { while true {} diff --git a/features/fixtures/shared/scenarios/AppHangFatalOnlyScenario.swift b/features/fixtures/shared/scenarios/AppHangFatalOnlyScenario.swift index 95e4f81cd..c5071c426 100644 --- a/features/fixtures/shared/scenarios/AppHangFatalOnlyScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangFatalOnlyScenario.swift @@ -9,9 +9,9 @@ class AppHangFatalOnlyScenario: Scenario { } override func run() { - NSLog("Hanging indefinitely...") + logDebug("Hanging indefinitely...") // Use asyncAfter to allow the Appium click event to be handled - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { while true {} } } diff --git a/features/fixtures/shared/scenarios/AppHangInTerminationScenario.swift b/features/fixtures/shared/scenarios/AppHangInTerminationScenario.swift index 8a3026f5e..63e7b8942 100644 --- a/features/fixtures/shared/scenarios/AppHangInTerminationScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangInTerminationScenario.swift @@ -27,7 +27,7 @@ class AppHangInTerminationScenario: Scenario { #endif NotificationCenter.default.addObserver(forName: willTerminate, object: nil, queue: nil) { - NSLog("Received \($0.name.rawValue), simulating an app hang...") + logDebug("Received \($0.name.rawValue), simulating an app hang...") Thread.sleep(forTimeInterval: 3) } diff --git a/features/fixtures/shared/scenarios/AppHangScenario.swift b/features/fixtures/shared/scenarios/AppHangScenario.swift index 6bcc202cc..5f3474afc 100644 --- a/features/fixtures/shared/scenarios/AppHangScenario.swift +++ b/features/fixtures/shared/scenarios/AppHangScenario.swift @@ -18,7 +18,7 @@ class AppHangScenario: Scenario { override func run() { Bugsnag.setContext("App Hang Scenario") let timeInterval = TimeInterval(eventMode!)! - NSLog("Simulating an app hang of \(timeInterval) seconds...") + logDebug("Simulating an app hang of \(timeInterval) seconds...") if timeInterval > 2 { Thread.sleep(forTimeInterval: 1.5) Bugsnag.leaveBreadcrumb(withMessage: "This breadcrumb was left during the hang, before detection") @@ -27,6 +27,6 @@ class AppHangScenario: Scenario { Thread.sleep(forTimeInterval: timeInterval) } Bugsnag.leaveBreadcrumb(withMessage: "This breadcrumb was left after the hang") - NSLog("Finished sleeping") + logDebug("Finished sleeping") } } diff --git a/features/fixtures/shared/scenarios/AsyncSafeMallocScenario.m b/features/fixtures/shared/scenarios/AsyncSafeMallocScenario.m index bf955a39a..35927083e 100644 --- a/features/fixtures/shared/scenarios/AsyncSafeMallocScenario.m +++ b/features/fixtures/shared/scenarios/AsyncSafeMallocScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" #include "spin_malloc.h" @interface AsyncSafeMallocScenario : Scenario diff --git a/features/fixtures/shared/scenarios/AsyncSafeThreadScenario.m b/features/fixtures/shared/scenarios/AsyncSafeThreadScenario.m index a72792f68..21469d72e 100644 --- a/features/fixtures/shared/scenarios/AsyncSafeThreadScenario.m +++ b/features/fixtures/shared/scenarios/AsyncSafeThreadScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import /** @@ -46,7 +47,7 @@ - (void)run { /* This is unreachable, but prevents clang from applying TCO to the above when * optimization is enabled. */ - NSLog(@"I'm here from the tail call prevention department."); + logInfo(@"I'm here from the tail call prevention department."); } @end diff --git a/features/fixtures/shared/scenarios/AttemptDeliveryOnCrashScenario.swift b/features/fixtures/shared/scenarios/AttemptDeliveryOnCrashScenario.swift index c3ccf1ae4..5dd2f1b03 100644 --- a/features/fixtures/shared/scenarios/AttemptDeliveryOnCrashScenario.swift +++ b/features/fixtures/shared/scenarios/AttemptDeliveryOnCrashScenario.swift @@ -28,7 +28,14 @@ class AttemptDeliveryOnCrashScenario: Scenario { break case "NSException": - NSArray().object(at: 42) + NSException( + name: .rangeException, + reason: "Something is out of range", + userInfo: [ + "date": Date(timeIntervalSinceReferenceDate: 0), + "scenario": "BareboneTestUnhandledErrorScenario", + NSUnderlyingErrorKey: NSError(domain: "ErrorDomain", code: 0)]) + .raise() break case "SwiftFatalError": diff --git a/features/fixtures/shared/scenarios/AutoCaptureRunScenario.m b/features/fixtures/shared/scenarios/AutoCaptureRunScenario.m index 21332dd4b..dc720615c 100644 --- a/features/fixtures/shared/scenarios/AutoCaptureRunScenario.m +++ b/features/fixtures/shared/scenarios/AutoCaptureRunScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoCaptureRunScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/AutoSessionCustomVersionScenario.m b/features/fixtures/shared/scenarios/AutoSessionCustomVersionScenario.m index f73ba2f34..a5ff35082 100644 --- a/features/fixtures/shared/scenarios/AutoSessionCustomVersionScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionCustomVersionScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoSessionCustomVersionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/AutoSessionHandledEventsScenario.m b/features/fixtures/shared/scenarios/AutoSessionHandledEventsScenario.m index 7f057ae89..79c36adb5 100644 --- a/features/fixtures/shared/scenarios/AutoSessionHandledEventsScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionHandledEventsScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoSessionHandledEventsScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m b/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m index fd03d0f2e..09bd7a1f5 100644 --- a/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoSessionMixedEventsScenario : Scenario diff --git a/features/fixtures/shared/scenarios/AutoSessionScenario.m b/features/fixtures/shared/scenarios/AutoSessionScenario.m index 49ef6d824..8ef94cb27 100644 --- a/features/fixtures/shared/scenarios/AutoSessionScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionScenario.m @@ -4,6 +4,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Sends an automatic session payload to Bugsnag. diff --git a/features/fixtures/shared/scenarios/AutoSessionUnhandledScenario.m b/features/fixtures/shared/scenarios/AutoSessionUnhandledScenario.m index d1eb8b40a..bbfd91200 100644 --- a/features/fixtures/shared/scenarios/AutoSessionUnhandledScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionUnhandledScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoSessionUnhandledScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/AutoSessionWithUserScenario.m b/features/fixtures/shared/scenarios/AutoSessionWithUserScenario.m index 0c70fc70d..4e951eaef 100644 --- a/features/fixtures/shared/scenarios/AutoSessionWithUserScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionWithUserScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface AutoSessionWithUserScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/BareboneTestHandledScenario.swift b/features/fixtures/shared/scenarios/BareboneTestHandledScenario.swift index 763a83822..ae7e85198 100644 --- a/features/fixtures/shared/scenarios/BareboneTestHandledScenario.swift +++ b/features/fixtures/shared/scenarios/BareboneTestHandledScenario.swift @@ -89,7 +89,7 @@ class BareboneTestHandledScenario: Scenario { """, key: "shouldBeTruncated", section: "Other") Bugsnag.notify(NSException(name: .rangeException, - reason: "-[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]", + reason: "Something is out of range", userInfo: ["date": Date(timeIntervalSinceReferenceDate: 0), "scenario": "BareboneTestHandledScenario", NSUnderlyingErrorKey: NSError(domain: "ErrorDomain", code: 0)])) { diff --git a/features/fixtures/shared/scenarios/BareboneTestUnhandledErrorScenario.swift b/features/fixtures/shared/scenarios/BareboneTestUnhandledErrorScenario.swift index 1c3c4d5f3..689505e39 100644 --- a/features/fixtures/shared/scenarios/BareboneTestUnhandledErrorScenario.swift +++ b/features/fixtures/shared/scenarios/BareboneTestUnhandledErrorScenario.swift @@ -33,7 +33,7 @@ class BareboneTestUnhandledErrorScenario: Scenario { // Manually constructing an exception to verify handling of userInfo NSException( name: .rangeException, - reason: "*** -[__NSArray0 objectAtIndex:]: index 42 beyond bounds for empty NSArray", + reason: "Something is out of range", userInfo: [ "date": Date(timeIntervalSinceReferenceDate: 0), "scenario": "BareboneTestUnhandledErrorScenario", diff --git a/features/fixtures/shared/scenarios/BreadcrumbCallbackRemovalScenario.m b/features/fixtures/shared/scenarios/BreadcrumbCallbackRemovalScenario.m index 30f19c8fa..7fd294638 100644 --- a/features/fixtures/shared/scenarios/BreadcrumbCallbackRemovalScenario.m +++ b/features/fixtures/shared/scenarios/BreadcrumbCallbackRemovalScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface BreadcrumbCallbackRemovalScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/BuiltinTrapScenario.m b/features/fixtures/shared/scenarios/BuiltinTrapScenario.m index 633260ad3..2018d978d 100644 --- a/features/fixtures/shared/scenarios/BuiltinTrapScenario.m +++ b/features/fixtures/shared/scenarios/BuiltinTrapScenario.m @@ -4,6 +4,7 @@ // #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/ConcurrentCrashesScenario.mm b/features/fixtures/shared/scenarios/ConcurrentCrashesScenario.mm index 5043fda71..c4b7f069a 100644 --- a/features/fixtures/shared/scenarios/ConcurrentCrashesScenario.mm +++ b/features/fixtures/shared/scenarios/ConcurrentCrashesScenario.mm @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" #import #import diff --git a/features/fixtures/shared/scenarios/CouldNotCreateDirectoryScenario.swift b/features/fixtures/shared/scenarios/CouldNotCreateDirectoryScenario.swift index 293f5dd22..e5e2f6c23 100644 --- a/features/fixtures/shared/scenarios/CouldNotCreateDirectoryScenario.swift +++ b/features/fixtures/shared/scenarios/CouldNotCreateDirectoryScenario.swift @@ -26,7 +26,7 @@ class CouldNotCreateDirectoryScenario: Scenario { try fileManager.setAttributes([.posixPermissions: 0o600], ofItemAtPath: dir.path) super.startBugsnag() } catch { - NSLog("\(error)") + logError("\(error)") } } diff --git a/features/fixtures/shared/scenarios/CustomPluginNotifierDescriptionScenario.m b/features/fixtures/shared/scenarios/CustomPluginNotifierDescriptionScenario.m index ef171cabc..0310e8832 100644 --- a/features/fixtures/shared/scenarios/CustomPluginNotifierDescriptionScenario.m +++ b/features/fixtures/shared/scenarios/CustomPluginNotifierDescriptionScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" @interface CustomPluginNotifierDescriptionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/CxxBareThrowScenario.mm b/features/fixtures/shared/scenarios/CxxBareThrowScenario.mm index 37a3f4e8f..cfd546e90 100644 --- a/features/fixtures/shared/scenarios/CxxBareThrowScenario.mm +++ b/features/fixtures/shared/scenarios/CxxBareThrowScenario.mm @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" #import @interface CxxBareThrowScenario : Scenario diff --git a/features/fixtures/shared/scenarios/CxxExceptionOverrideScenario.mm b/features/fixtures/shared/scenarios/CxxExceptionOverrideScenario.mm index 888d07d16..cc487d97f 100644 --- a/features/fixtures/shared/scenarios/CxxExceptionOverrideScenario.mm +++ b/features/fixtures/shared/scenarios/CxxExceptionOverrideScenario.mm @@ -25,6 +25,7 @@ */ #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/CxxExceptionScenario.mm b/features/fixtures/shared/scenarios/CxxExceptionScenario.mm index 168d426d7..e9b6a362d 100644 --- a/features/fixtures/shared/scenarios/CxxExceptionScenario.mm +++ b/features/fixtures/shared/scenarios/CxxExceptionScenario.mm @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/CxxUnexpectedScenario.mm b/features/fixtures/shared/scenarios/CxxUnexpectedScenario.mm index 7f6fd4fe9..334c25449 100644 --- a/features/fixtures/shared/scenarios/CxxUnexpectedScenario.mm +++ b/features/fixtures/shared/scenarios/CxxUnexpectedScenario.mm @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" #import @interface CxxUnexpectedScenario : Scenario diff --git a/features/fixtures/shared/scenarios/DisableAllExceptManualExceptionsAndCrashScenario.m b/features/fixtures/shared/scenarios/DisableAllExceptManualExceptionsAndCrashScenario.m index 00df4ff33..254075afd 100644 --- a/features/fixtures/shared/scenarios/DisableAllExceptManualExceptionsAndCrashScenario.m +++ b/features/fixtures/shared/scenarios/DisableAllExceptManualExceptionsAndCrashScenario.m @@ -9,6 +9,7 @@ // C++ crashes are handled in a separate scenario, and OOM is not tested for. #import "Scenario.h" +#import "Logging.h" /** * Disable all crash reporting (except, implicitly, manual) and crash the app diff --git a/features/fixtures/shared/scenarios/DisableMachExceptionScenario.m b/features/fixtures/shared/scenarios/DisableMachExceptionScenario.m index 77fa2ed9b..a4401ec8c 100644 --- a/features/fixtures/shared/scenarios/DisableMachExceptionScenario.m +++ b/features/fixtures/shared/scenarios/DisableMachExceptionScenario.m @@ -9,6 +9,7 @@ // C++ crashes are handled in a separate scenario, and OOM is not tested for. #import "Scenario.h" +#import "Logging.h" @interface DisableMachExceptionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/DisableNSExceptionScenario.m b/features/fixtures/shared/scenarios/DisableNSExceptionScenario.m index 823173a54..e5cdf9be7 100644 --- a/features/fixtures/shared/scenarios/DisableNSExceptionScenario.m +++ b/features/fixtures/shared/scenarios/DisableNSExceptionScenario.m @@ -9,6 +9,7 @@ // C++ crashes are handled in a separate scenario, and OOM is not tested for. #import "Scenario.h" +#import "Logging.h" @interface DisableNSExceptionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/DisableSignalsExceptionScenario.m b/features/fixtures/shared/scenarios/DisableSignalsExceptionScenario.m index ed4c2cb10..22d3ff90b 100644 --- a/features/fixtures/shared/scenarios/DisableSignalsExceptionScenario.m +++ b/features/fixtures/shared/scenarios/DisableSignalsExceptionScenario.m @@ -9,6 +9,7 @@ // C++ crashes are handled in a separate scenario, and OOM is not tested for. #import "Scenario.h" +#import "Logging.h" @interface DisableSignalsExceptionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/DisabledSessionTrackingScenario.m b/features/fixtures/shared/scenarios/DisabledSessionTrackingScenario.m index e3c378446..cc87e35db 100644 --- a/features/fixtures/shared/scenarios/DisabledSessionTrackingScenario.m +++ b/features/fixtures/shared/scenarios/DisabledSessionTrackingScenario.m @@ -4,6 +4,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface DisabledSessionTrackingScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm b/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm index c424d9f1a..f09a10a01 100644 --- a/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm +++ b/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/HandledErrorThreadSendAlwaysScenario.m b/features/fixtures/shared/scenarios/HandledErrorThreadSendAlwaysScenario.m index c6b936dfc..30b657b4b 100644 --- a/features/fixtures/shared/scenarios/HandledErrorThreadSendAlwaysScenario.m +++ b/features/fixtures/shared/scenarios/HandledErrorThreadSendAlwaysScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface HandledErrorThreadSendAlwaysScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/HandledErrorThreadSendUnhandledOnlyScenario.m b/features/fixtures/shared/scenarios/HandledErrorThreadSendUnhandledOnlyScenario.m index 94a0d7d39..63432ec7a 100644 --- a/features/fixtures/shared/scenarios/HandledErrorThreadSendUnhandledOnlyScenario.m +++ b/features/fixtures/shared/scenarios/HandledErrorThreadSendUnhandledOnlyScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface HandledErrorThreadSendUnhandledOnlyScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/InvalidCrashReportScenario.m b/features/fixtures/shared/scenarios/InvalidCrashReportScenario.m index f8719868a..19c3118c8 100644 --- a/features/fixtures/shared/scenarios/InvalidCrashReportScenario.m +++ b/features/fixtures/shared/scenarios/InvalidCrashReportScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface InvalidCrashReportScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/LastRunInfoScenario.swift b/features/fixtures/shared/scenarios/LastRunInfoScenario.swift index 735bbed14..4995e7b7e 100644 --- a/features/fixtures/shared/scenarios/LastRunInfoScenario.swift +++ b/features/fixtures/shared/scenarios/LastRunInfoScenario.swift @@ -46,7 +46,7 @@ class LastRunInfoScenario: Scenario { while try! !FileManager.default.contentsOfDirectory(at: dir, includingPropertiesForKeys: nil, options: []) .filter({ $0.lastPathComponent.hasPrefix("CrashReport-") }).isEmpty { - NSLog("LastRunInfoScenario: waiting for delivery of crash reports...") + logDebug("LastRunInfoScenario: waiting for delivery of crash reports...") Thread.sleep(forTimeInterval: 0.1) } } diff --git a/features/fixtures/shared/scenarios/Logging.h b/features/fixtures/shared/scenarios/Logging.h new file mode 100644 index 000000000..6305e7eac --- /dev/null +++ b/features/fixtures/shared/scenarios/Logging.h @@ -0,0 +1,23 @@ +// +// Logging.h +// iOSTestApp +// +// Created by Karl Stenerud on 02.11.23. +// Copyright © 2023 Bugsnag. All rights reserved. +// + +#import + +void logDebugObjC(NSString *format, ...); +void logInfoObjC(NSString *format, ...); +void logWarnObjC(NSString *format, ...); +void logErrorObjC(NSString *format, ...); + +//#define logInfo(FMT, ...) logInfoObjC(FMT, __VA_ARGS__) +//#define logWarn(FMT, ...) logWarnObjC(FMT, __VA_ARGS__) +//#define logError(FMT, ...) logErrorObjC(FMT, __VA_ARGS__) + +#define logDebug logDebugObjC +#define logInfo logInfoObjC +#define logWarn logWarnObjC +#define logError logErrorObjC diff --git a/features/fixtures/shared/scenarios/Logging.m b/features/fixtures/shared/scenarios/Logging.m new file mode 100644 index 000000000..742201d72 --- /dev/null +++ b/features/fixtures/shared/scenarios/Logging.m @@ -0,0 +1,51 @@ +// +// Logging.m +// iOSTestApp +// +// Created by Karl Stenerud on 02.11.23. +// Copyright © 2023 Bugsnag. All rights reserved. +// + +#import "Logging.h" + +extern void bsg_i_kslog_logCBasic(const char *fmt, ...) __printflike(1, 2); + +void logInternal(const char* level, NSString *format, va_list args) { + NSString *formatted = [[NSString alloc] initWithFormat:format arguments:args]; + NSString *fullMessage = [NSString stringWithFormat:@"bugsnagci %s: %@", level, formatted]; + + NSLog(@"%@", fullMessage); + bsg_i_kslog_logCBasic("%s", + [[NSString stringWithFormat:@"%@ %@", + [NSDate date], fullMessage] + cStringUsingEncoding:NSUTF8StringEncoding]); + +} + +void logDebugObjC(NSString *format, ...) { + va_list args; + va_start(args, format); + logInternal("debug", format, args); + va_end(args); +} + +void logInfoObjC(NSString *format, ...) { + va_list args; + va_start(args, format); + logInternal("info", format, args); + va_end(args); +} + +void logWarnObjC(NSString *format, ...) { + va_list args; + va_start(args, format); + logInternal("warn", format, args); + va_end(args); +} + +void logErrorObjC(NSString *format, ...) { + va_list args; + va_start(args, format); + logInternal("error", format, args); + va_end(args); +} diff --git a/features/fixtures/shared/scenarios/ManualSessionScenario.m b/features/fixtures/shared/scenarios/ManualSessionScenario.m index 2bd7283ad..26c912d2e 100644 --- a/features/fixtures/shared/scenarios/ManualSessionScenario.m +++ b/features/fixtures/shared/scenarios/ManualSessionScenario.m @@ -4,6 +4,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Sends a manual session payload to Bugsnag. diff --git a/features/fixtures/shared/scenarios/ManualSessionWithUserScenario.m b/features/fixtures/shared/scenarios/ManualSessionWithUserScenario.m index dd4ca4b8b..842a028b9 100644 --- a/features/fixtures/shared/scenarios/ManualSessionWithUserScenario.m +++ b/features/fixtures/shared/scenarios/ManualSessionWithUserScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface ManualSessionWithUserScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/ManyConcurrentNotifyScenario.m b/features/fixtures/shared/scenarios/ManyConcurrentNotifyScenario.m index 97330e1e8..a4904b226 100644 --- a/features/fixtures/shared/scenarios/ManyConcurrentNotifyScenario.m +++ b/features/fixtures/shared/scenarios/ManyConcurrentNotifyScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" @interface ManyConcurrentNotifyScenario : Scenario @property (nonatomic) dispatch_queue_t queue1; diff --git a/features/fixtures/shared/scenarios/MarkUnhandledHandledScenario.m b/features/fixtures/shared/scenarios/MarkUnhandledHandledScenario.m index d394089ab..83e4cb409 100644 --- a/features/fixtures/shared/scenarios/MarkUnhandledHandledScenario.m +++ b/features/fixtures/shared/scenarios/MarkUnhandledHandledScenario.m @@ -7,6 +7,7 @@ // #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" @implementation MarkUnhandledHandledScenario diff --git a/features/fixtures/shared/scenarios/MaxPersistedSessionsScenario.m b/features/fixtures/shared/scenarios/MaxPersistedSessionsScenario.m index 3b308879a..f39155546 100644 --- a/features/fixtures/shared/scenarios/MaxPersistedSessionsScenario.m +++ b/features/fixtures/shared/scenarios/MaxPersistedSessionsScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface MaxPersistedSessionsScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/NSExceptionShiftScenario.m b/features/fixtures/shared/scenarios/NSExceptionShiftScenario.m index 7bb440161..e1b0d059b 100644 --- a/features/fixtures/shared/scenarios/NSExceptionShiftScenario.m +++ b/features/fixtures/shared/scenarios/NSExceptionShiftScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" @interface NSExceptionShiftScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/NonExistentMethodScenario.m b/features/fixtures/shared/scenarios/NonExistentMethodScenario.m index 3716d5bde..8990d003c 100644 --- a/features/fixtures/shared/scenarios/NonExistentMethodScenario.m +++ b/features/fixtures/shared/scenarios/NonExistentMethodScenario.m @@ -4,6 +4,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Calls a non-existent method on an object diff --git a/features/fixtures/shared/scenarios/NullPointerScenario.m b/features/fixtures/shared/scenarios/NullPointerScenario.m index 852e169f4..81318f063 100644 --- a/features/fixtures/shared/scenarios/NullPointerScenario.m +++ b/features/fixtures/shared/scenarios/NullPointerScenario.m @@ -24,6 +24,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/OOMInactiveScenario.swift b/features/fixtures/shared/scenarios/OOMInactiveScenario.swift index 648286580..a9b496b36 100644 --- a/features/fixtures/shared/scenarios/OOMInactiveScenario.swift +++ b/features/fixtures/shared/scenarios/OOMInactiveScenario.swift @@ -22,7 +22,7 @@ class OOMInactiveScenario: Scenario { NotificationCenter.default.post(name: UIApplication.willResignActiveNotification, object: UIApplication.shared, userInfo: nil) - NSLog("Killing app to fake an OOM") + logDebug("Killing app to fake an OOM") kill(getpid(), SIGKILL) } } diff --git a/features/fixtures/shared/scenarios/OOMScenario.m b/features/fixtures/shared/scenarios/OOMScenario.m index b32b8d592..e5f0622f6 100644 --- a/features/fixtures/shared/scenarios/OOMScenario.m +++ b/features/fixtures/shared/scenarios/OOMScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" #import @@ -57,7 +58,7 @@ - (void)run { [Bugsnag setContext:@"OOM Scenario"]; [NSNotificationCenter.defaultCenter addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:nil usingBlock:^(NSNotification *note) { - NSLog(@"*** Received memory warning"); + logDebug(@"*** Received memory warning"); }]; // Delay to allow session payload to be sent [self performSelector:@selector(consumeAllMemory) withObject:nil afterDelay:2]; @@ -66,11 +67,11 @@ - (void)run { - (void)consumeAllMemory { struct utsname system = {0}; uname(&system); - NSLog(@"*** Device = %s", system.machine); + logDebug(@"*** Device = %s", system.machine); NSUInteger physicalMemory = (NSUInteger)NSProcessInfo.processInfo.physicalMemory; NSUInteger megabytes = physicalMemory / MEGABYTE; - NSLog(@"*** Physical memory = %lu MB", (unsigned long)megabytes); + logDebug(@"*** Physical memory = %lu MB", (unsigned long)megabytes); // // The ActiveHard limit and point at which a memory warning is sent varies by device @@ -104,21 +105,21 @@ - (void)consumeAllMemory { kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &count); if (result == KERN_SUCCESS && count >= TASK_VM_INFO_REV4_COUNT) { limit = (NSUInteger)(vm_info.phys_footprint + vm_info.limit_bytes_remaining) / MEGABYTE; - NSLog(@"*** Memory limit = %lu MB", (unsigned long)limit); + logDebug(@"*** Memory limit = %lu MB", (unsigned long)limit); } else if (!strcmp(system.machine, "iPhone6,2")) { limit = 650; - NSLog(@"*** Memory limit = %lu MB", (unsigned long)limit); + logDebug(@"*** Memory limit = %lu MB", (unsigned long)limit); } else { limit = MIN(2098, megabytes * 70 / 100); - NSLog(@"*** Memory limit = %lu MB (estimated)", (unsigned long)limit); + logDebug(@"*** Memory limit = %lu MB (estimated)", (unsigned long)limit); } // The size of the initial block needs to be under the memory warning limit in order for one to be reliably sent. NSUInteger initial = limit * 70 / 100; - NSLog(@"*** Dirtying an initial block of %lu MB", (unsigned long)initial); + logDebug(@"*** Dirtying an initial block of %lu MB", (unsigned long)initial); [self consumeMegabytes:initial]; - NSLog(@"*** Dirtying remaining memory in ~2 seconds"); + logDebug(@"*** Dirtying remaining memory in ~2 seconds"); NSTimeInterval timeInterval = 2.0 / (limit - initial); [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(timerFired) userInfo:nil repeats:YES]; } diff --git a/features/fixtures/shared/scenarios/OOMSessionlessScenario.m b/features/fixtures/shared/scenarios/OOMSessionlessScenario.m index 4b9c4c305..eff7e4904 100644 --- a/features/fixtures/shared/scenarios/OOMSessionlessScenario.m +++ b/features/fixtures/shared/scenarios/OOMSessionlessScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface OOMSessionlessScenario : Scenario diff --git a/features/fixtures/shared/scenarios/OOMWillTerminateScenario.m b/features/fixtures/shared/scenarios/OOMWillTerminateScenario.m index 072a3cb5a..4c8e0eedf 100644 --- a/features/fixtures/shared/scenarios/OOMWillTerminateScenario.m +++ b/features/fixtures/shared/scenarios/OOMWillTerminateScenario.m @@ -1,5 +1,6 @@ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/ObjCExceptionOverrideScenario.m b/features/fixtures/shared/scenarios/ObjCExceptionOverrideScenario.m index 4b25d51de..5ab2177c4 100644 --- a/features/fixtures/shared/scenarios/ObjCExceptionOverrideScenario.m +++ b/features/fixtures/shared/scenarios/ObjCExceptionOverrideScenario.m @@ -25,6 +25,7 @@ */ #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" /** * Throw an uncaught Objective-C exception. It's possible to generate a better crash report here diff --git a/features/fixtures/shared/scenarios/ObjCExceptionScenario.m b/features/fixtures/shared/scenarios/ObjCExceptionScenario.m index 4e889d96b..b7e491c63 100644 --- a/features/fixtures/shared/scenarios/ObjCExceptionScenario.m +++ b/features/fixtures/shared/scenarios/ObjCExceptionScenario.m @@ -25,6 +25,7 @@ */ #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" /** * Throw an uncaught Objective-C exception. It's possible to generate a better crash report here diff --git a/features/fixtures/shared/scenarios/ObjCMsgSendScenario.m b/features/fixtures/shared/scenarios/ObjCMsgSendScenario.m index d272b1c33..eb8c9cb06 100644 --- a/features/fixtures/shared/scenarios/ObjCMsgSendScenario.m +++ b/features/fixtures/shared/scenarios/ObjCMsgSendScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/OldCrashReportScenario.swift b/features/fixtures/shared/scenarios/OldCrashReportScenario.swift index 7ad986648..48de226cd 100644 --- a/features/fixtures/shared/scenarios/OldCrashReportScenario.swift +++ b/features/fixtures/shared/scenarios/OldCrashReportScenario.swift @@ -24,10 +24,10 @@ class OldCrashReportScenario: Scenario { for name in try FileManager.default.contentsOfDirectory(atPath: dir) { let file = (dir as NSString).appendingPathComponent(name) try FileManager.default.setAttributes([.creationDate: creationDate], ofItemAtPath: file) - NSLog("OldCrashReportScenario: Updated creation date of \((file as NSString).lastPathComponent) to \(creationDate)") + logDebug("OldCrashReportScenario: Updated creation date of \((file as NSString).lastPathComponent) to \(creationDate)") } } catch { - NSLog("\(error)") + logError("\(error)") } } } diff --git a/features/fixtures/shared/scenarios/OldHandledErrorScenario.swift b/features/fixtures/shared/scenarios/OldHandledErrorScenario.swift index e3dfc2fc7..499a1995e 100644 --- a/features/fixtures/shared/scenarios/OldHandledErrorScenario.swift +++ b/features/fixtures/shared/scenarios/OldHandledErrorScenario.swift @@ -24,10 +24,10 @@ class OldHandledErrorScenario: Scenario { for name in try FileManager.default.contentsOfDirectory(atPath: dir) { let file = (dir as NSString).appendingPathComponent(name) try FileManager.default.setAttributes([.creationDate: creationDate], ofItemAtPath: file) - NSLog("OldCrashReportScenario: Updated creation date of \((file as NSString).lastPathComponent) to \(creationDate)") + logDebug("OldCrashReportScenario: Updated creation date of \((file as NSString).lastPathComponent) to \(creationDate)") } } catch { - NSLog("\(error)") + logError("\(error)") } } } diff --git a/features/fixtures/shared/scenarios/OldSessionScenario.m b/features/fixtures/shared/scenarios/OldSessionScenario.m index 07f1149ed..2aca8e73c 100644 --- a/features/fixtures/shared/scenarios/OldSessionScenario.m +++ b/features/fixtures/shared/scenarios/OldSessionScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface OldSessionScenario : Scenario @end @@ -40,10 +41,10 @@ - (void)modifySessionCreationDate { NSString *file = [dir stringByAppendingPathComponent:name]; NSError *error; if ([NSFileManager.defaultManager setAttributes:@{NSFileCreationDate: creationDate} ofItemAtPath:file error:&error]) { - NSLog(@"OldSessionScenario: Updated creation date of %@ to %@", file.lastPathComponent, + logDebug(@"OldSessionScenario: Updated creation date of %@ to %@", file.lastPathComponent, [NSFileManager.defaultManager attributesOfItemAtPath:file error:nil].fileCreationDate); } else { - NSLog(@"OldSessionScenario: %@", error); + logError(@"OldSessionScenario: %@", error); abort(); } } diff --git a/features/fixtures/shared/scenarios/OnCrashHandlerScenario.m b/features/fixtures/shared/scenarios/OnCrashHandlerScenario.m index abd9a739b..edd7b4c32 100644 --- a/features/fixtures/shared/scenarios/OnCrashHandlerScenario.m +++ b/features/fixtures/shared/scenarios/OnCrashHandlerScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" // Create crash handler void HandleCrashedThread(const BSG_KSCrashReportWriter *writer) { diff --git a/features/fixtures/shared/scenarios/OnSendCallbackRemovalScenario.m b/features/fixtures/shared/scenarios/OnSendCallbackRemovalScenario.m index 92aa94a52..aa1f3f7ed 100644 --- a/features/fixtures/shared/scenarios/OnSendCallbackRemovalScenario.m +++ b/features/fixtures/shared/scenarios/OnSendCallbackRemovalScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Verifies that removing an OnSend callback does not affect other OnSend callbacks diff --git a/features/fixtures/shared/scenarios/OnSendErrorPersistenceScenario.m b/features/fixtures/shared/scenarios/OnSendErrorPersistenceScenario.m index 340549f21..a59c953a5 100644 --- a/features/fixtures/shared/scenarios/OnSendErrorPersistenceScenario.m +++ b/features/fixtures/shared/scenarios/OnSendErrorPersistenceScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" NSString * const HasNotifiedKey = @"OnSendErrorPersistenceScenario.hasNotified"; diff --git a/features/fixtures/shared/scenarios/OverwriteLinkRegisterScenario.m b/features/fixtures/shared/scenarios/OverwriteLinkRegisterScenario.m index 53cdeb56d..6aa1f2284 100644 --- a/features/fixtures/shared/scenarios/OverwriteLinkRegisterScenario.m +++ b/features/fixtures/shared/scenarios/OverwriteLinkRegisterScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/PrivilegedInstructionScenario.m b/features/fixtures/shared/scenarios/PrivilegedInstructionScenario.m index 445c2029a..2860f5311 100644 --- a/features/fixtures/shared/scenarios/PrivilegedInstructionScenario.m +++ b/features/fixtures/shared/scenarios/PrivilegedInstructionScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/ReadGarbagePointerScenario.m b/features/fixtures/shared/scenarios/ReadGarbagePointerScenario.m index 071e75d94..1c50c0509 100644 --- a/features/fixtures/shared/scenarios/ReadGarbagePointerScenario.m +++ b/features/fixtures/shared/scenarios/ReadGarbagePointerScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/ReadOnlyPageScenario.m b/features/fixtures/shared/scenarios/ReadOnlyPageScenario.m index 840a65cca..0ebfeb63b 100644 --- a/features/fixtures/shared/scenarios/ReadOnlyPageScenario.m +++ b/features/fixtures/shared/scenarios/ReadOnlyPageScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/RecrashScenarios.mm b/features/fixtures/shared/scenarios/RecrashScenarios.mm index 7cb12d0d2..da496aa9b 100644 --- a/features/fixtures/shared/scenarios/RecrashScenarios.mm +++ b/features/fixtures/shared/scenarios/RecrashScenarios.mm @@ -7,11 +7,15 @@ // #import "Scenario.h" +#import "Logging.h" #import #define THROW_CPP_EXCEPTION throw std::runtime_error("err") -#define THROW_OBJC_EXCEPTION [@[] objectAtIndex:42] +#define THROW_OBJC_EXCEPTION \ + [[NSException exceptionWithName:NSRangeException \ + reason:@"Something is out of range" \ + userInfo:nil] raise] #define CAUSE_MACH_EXCEPTION volatile int *ptr = NULL; *ptr = 42 #define RAISE_SIGNAL abort() diff --git a/features/fixtures/shared/scenarios/ReleasedObjectScenario.m b/features/fixtures/shared/scenarios/ReleasedObjectScenario.m index 5f1518901..75a098378 100644 --- a/features/fixtures/shared/scenarios/ReleasedObjectScenario.m +++ b/features/fixtures/shared/scenarios/ReleasedObjectScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/ReportBackgroundAppHangScenario.swift b/features/fixtures/shared/scenarios/ReportBackgroundAppHangScenario.swift index 247b0211a..cc98ee1f1 100644 --- a/features/fixtures/shared/scenarios/ReportBackgroundAppHangScenario.swift +++ b/features/fixtures/shared/scenarios/ReportBackgroundAppHangScenario.swift @@ -19,11 +19,11 @@ class ReportBackgroundAppHangScenario: Scenario { let backgroundTask = UIApplication.shared.beginBackgroundTask() let timeInterval: TimeInterval = 2 - NSLog("Simulating an app hang of \(timeInterval) seconds...") + logDebug("Simulating an app hang of \(timeInterval) seconds...") Thread.sleep(forTimeInterval: timeInterval) - NSLog("Finished sleeping") + logDebug("Finished sleeping") - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { UIApplication.shared.endBackgroundTask(backgroundTask) } } diff --git a/features/fixtures/shared/scenarios/ResumeSessionOOMScenario.m b/features/fixtures/shared/scenarios/ResumeSessionOOMScenario.m index 0b7cdc886..9c7aeacc5 100644 --- a/features/fixtures/shared/scenarios/ResumeSessionOOMScenario.m +++ b/features/fixtures/shared/scenarios/ResumeSessionOOMScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" @interface ResumeSessionOOMScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGBUSScenario.m b/features/fixtures/shared/scenarios/SIGBUSScenario.m index f777264f6..6d974de38 100644 --- a/features/fixtures/shared/scenarios/SIGBUSScenario.m +++ b/features/fixtures/shared/scenarios/SIGBUSScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGBUSScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGFPEScenario.m b/features/fixtures/shared/scenarios/SIGFPEScenario.m index ac1ba04ae..193cbd9a5 100644 --- a/features/fixtures/shared/scenarios/SIGFPEScenario.m +++ b/features/fixtures/shared/scenarios/SIGFPEScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGFPEScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGILLScenario.m b/features/fixtures/shared/scenarios/SIGILLScenario.m index 3d3926726..0b43f8536 100644 --- a/features/fixtures/shared/scenarios/SIGILLScenario.m +++ b/features/fixtures/shared/scenarios/SIGILLScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGILLScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGPIPEIgnoredScenario.m b/features/fixtures/shared/scenarios/SIGPIPEIgnoredScenario.m index 13f973a53..9a5dd01d5 100644 --- a/features/fixtures/shared/scenarios/SIGPIPEIgnoredScenario.m +++ b/features/fixtures/shared/scenarios/SIGPIPEIgnoredScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGPIPEIgnoredScenario : Scenario diff --git a/features/fixtures/shared/scenarios/SIGPIPEScenario.m b/features/fixtures/shared/scenarios/SIGPIPEScenario.m index 2a3c9ef34..be4696c12 100644 --- a/features/fixtures/shared/scenarios/SIGPIPEScenario.m +++ b/features/fixtures/shared/scenarios/SIGPIPEScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGPIPEScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGSEGVScenario.m b/features/fixtures/shared/scenarios/SIGSEGVScenario.m index 7ced08c05..667eb4569 100644 --- a/features/fixtures/shared/scenarios/SIGSEGVScenario.m +++ b/features/fixtures/shared/scenarios/SIGSEGVScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGSEGVScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGSYSScenario.m b/features/fixtures/shared/scenarios/SIGSYSScenario.m index 322e3bbe6..607c9919c 100644 --- a/features/fixtures/shared/scenarios/SIGSYSScenario.m +++ b/features/fixtures/shared/scenarios/SIGSYSScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGSYSScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SIGTRAPScenario.m b/features/fixtures/shared/scenarios/SIGTRAPScenario.m index 3bee4645f..c8ca433a2 100644 --- a/features/fixtures/shared/scenarios/SIGTRAPScenario.m +++ b/features/fixtures/shared/scenarios/SIGTRAPScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SIGTRAPScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/Scenario.h b/features/fixtures/shared/scenarios/Scenario.h index a419f8247..9f05796f9 100644 --- a/features/fixtures/shared/scenarios/Scenario.h +++ b/features/fixtures/shared/scenarios/Scenario.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN -void kslog(const char *message); +void logInternal(const char* level, NSString *format, va_list args); void markErrorHandledCallback(const BSG_KSCrashReportWriter *writer); diff --git a/features/fixtures/shared/scenarios/Scenario.m b/features/fixtures/shared/scenarios/Scenario.m index b80a1570a..7f2f20fae 100644 --- a/features/fixtures/shared/scenarios/Scenario.m +++ b/features/fixtures/shared/scenarios/Scenario.m @@ -3,6 +3,7 @@ // Copyright (c) 2018 Bugsnag. All rights reserved. // #import "Scenario.h" +#import "Logging.h" #import @@ -19,12 +20,6 @@ extern bool bsg_kslog_setLogFilename(const char *filename, bool overwrite); -extern void bsg_i_kslog_logCBasic(const char *fmt, ...) __printflike(1, 2); - -void kslog(const char *message) { - bsg_i_kslog_logCBasic("%s", message); -} - void markErrorHandledCallback(const BSG_KSCrashReportWriter *writer) { writer->addBooleanElement(writer, "unhandled", false); } @@ -65,7 +60,7 @@ + (void)load { return; } #endif - NSLog(@"%@", notification.name); + logDebug(@"Received notification %@", notification.name); }]; } @@ -184,7 +179,7 @@ + (void)initialize { } + (void)clearPersistentData { - NSLog(@"%s", __PRETTY_FUNCTION__); + logInfo(@"%s", __PRETTY_FUNCTION__); [NSUserDefaults.standardUserDefaults removePersistentDomainForName:NSBundle.mainBundle.bundleIdentifier]; NSString *cachesDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; NSArray *entries = @[ @@ -200,7 +195,7 @@ + (void)clearPersistentData { NSError *error = nil; if (![NSFileManager.defaultManager removeItemAtPath:path error:&error]) { if (![error.domain isEqualToString:NSCocoaErrorDomain] && error.code != NSFileNoSuchFileError) { - NSLog(@"%@", error); + logError(@"Error removing path %@: %@", path, error); } } } @@ -209,7 +204,7 @@ + (void)clearPersistentData { NSError *error = nil; if (![NSFileManager.defaultManager removeItemAtPath:rootDir error:&error]) { if (![error.domain isEqualToString:NSCocoaErrorDomain] && error.code != NSFileNoSuchFileError) { - NSLog(@"%@", error); + logError(@"Error removing path %@: %@", rootDir, error); } } #if !TARGET_OS_WATCH @@ -218,26 +213,29 @@ + (void)clearPersistentData { } + (void)executeMazeRunnerCommand:(void (^)(NSString *scenarioName, NSString *scenarioMode))preHandler { - NSLog(@"%s", __PRETTY_FUNCTION__); + logDebug(@"%s", __PRETTY_FUNCTION__); NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; NSString *commandEndpoint = [NSString stringWithFormat:@"%@/command", theBaseMazeAddress]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:commandEndpoint]]; + logDebug(@"%s: Sending command request to %@", __PRETTY_FUNCTION__, commandEndpoint); [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (![response isKindOfClass:[NSHTTPURLResponse class]] || [(NSHTTPURLResponse *)response statusCode] != 200) { - NSLog(@"%s request failed with %@", __PRETTY_FUNCTION__, response ?: error); + logError(@"%s: command request failed with %@", __PRETTY_FUNCTION__, response ?: error); + preHandler(@"", NULL); return; } - NSLog(@"%s response body: %@", __PRETTY_FUNCTION__, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + logInfo(@"%s: command response body: %@", __PRETTY_FUNCTION__, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); NSDictionary *command = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; NSString *action = [command objectForKey:@"action"]; + NSParameterAssert([action isKindOfClass:[NSString class]]); + if ([action isEqualToString:@"noop"]) { - NSLog(@"No Maze Runner command queued at present"); + logInfo(@"%s: No Maze Runner command queued at present", __PRETTY_FUNCTION__); + preHandler(@"", NULL); return; } - - NSParameterAssert([action isKindOfClass:[NSString class]]); - + NSString *scenarioName = [command objectForKey:@"scenario_name"]; NSParameterAssert([scenarioName isKindOfClass:[NSString class]]); @@ -268,7 +266,7 @@ + (void)executeMazeRunnerCommand:(void (^)(NSString *scenarioName, NSString *sce } + (void)runScenario:(NSString *)scenarioName eventMode:(NSString *)eventMode { - NSLog(@"%s %@ %@", __PRETTY_FUNCTION__, scenarioName, eventMode); + logDebug(@"%s %@ %@", __PRETTY_FUNCTION__, scenarioName, eventMode); [self startBugsnagForScenario:scenarioName eventMode:eventMode]; @@ -276,12 +274,12 @@ + (void)runScenario:(NSString *)scenarioName eventMode:(NSString *)eventMode { } + (void)startBugsnagForScenario:(NSString *)scenarioName eventMode:(NSString *)eventMode { - NSLog(@"%s %@ %@", __PRETTY_FUNCTION__, scenarioName, eventMode); + logDebug(@"%s %@ %@", __PRETTY_FUNCTION__, scenarioName, eventMode); theScenario = [Scenario createScenarioNamed:scenarioName withConfig:nil]; theScenario.eventMode = eventMode; - NSLog(@"Starting scenario \"%@\"", NSStringFromClass([self class])); + logInfo(@"%s: Starting scenario \"%@\"", __PRETTY_FUNCTION__, NSStringFromClass([self class])); [theScenario startBugsnag]; } diff --git a/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyLaunchCompletedScenario.swift b/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyLaunchCompletedScenario.swift index 721899bba..1c9b1ce3e 100644 --- a/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyLaunchCompletedScenario.swift +++ b/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyLaunchCompletedScenario.swift @@ -2,7 +2,7 @@ class SendLaunchCrashesSynchronouslyLaunchCompletedScenario: SendLaunchCrashesSy override func run() { if eventMode != "report" { - NSLog(">>> Calling markLaunchCompleted()") + logDebug(">>> Calling markLaunchCompleted()") Bugsnag.markLaunchCompleted() } super.run() diff --git a/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyScenario.swift b/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyScenario.swift index 0ffe6a7d7..ff3111a9c 100644 --- a/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyScenario.swift +++ b/features/fixtures/shared/scenarios/SendLaunchCrashesSynchronouslyScenario.swift @@ -20,7 +20,7 @@ class SendLaunchCrashesSynchronouslyScenario: Scenario { override func run() { if eventMode == "report" { - NSLog(">>> Delaying to allow previous run's crash report to be sent") + logDebug(">>> Delaying to allow previous run's crash report to be sent") DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [startDuration] in NSLog(">>> Calling notify() with startDuration = \(startDuration)") Bugsnag.notifyError(NSError(domain: "DummyError", code: 0)) { @@ -29,7 +29,7 @@ class SendLaunchCrashesSynchronouslyScenario: Scenario { } } } else { - NSLog(">>> Calling fatalError()") + logDebug(">>> Calling fatalError()") fatalError() } } diff --git a/features/fixtures/shared/scenarios/SessionCallbackRemovalScenario.m b/features/fixtures/shared/scenarios/SessionCallbackRemovalScenario.m index c8b7df6d0..49b49e780 100644 --- a/features/fixtures/shared/scenarios/SessionCallbackRemovalScenario.m +++ b/features/fixtures/shared/scenarios/SessionCallbackRemovalScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface SessionCallbackRemovalScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/SessionOOMScenario.m b/features/fixtures/shared/scenarios/SessionOOMScenario.m index 38294aaf4..70d071ebc 100644 --- a/features/fixtures/shared/scenarios/SessionOOMScenario.m +++ b/features/fixtures/shared/scenarios/SessionOOMScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" #import diff --git a/features/fixtures/shared/scenarios/StackOverflowScenario.m b/features/fixtures/shared/scenarios/StackOverflowScenario.m index 3b3560550..8d5b06de3 100644 --- a/features/fixtures/shared/scenarios/StackOverflowScenario.m +++ b/features/fixtures/shared/scenarios/StackOverflowScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" /** * Execute an infinitely recursive method, which overflows the stack and diff --git a/features/fixtures/shared/scenarios/StopSessionOOMScenario.m b/features/fixtures/shared/scenarios/StopSessionOOMScenario.m index 44a7d9a2f..a23df8904 100644 --- a/features/fixtures/shared/scenarios/StopSessionOOMScenario.m +++ b/features/fixtures/shared/scenarios/StopSessionOOMScenario.m @@ -1,4 +1,5 @@ #import "Scenario.h" +#import "Logging.h" @interface StopSessionOOMScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/UndefinedInstructionScenario.m b/features/fixtures/shared/scenarios/UndefinedInstructionScenario.m index 26325cf71..8a242e95a 100644 --- a/features/fixtures/shared/scenarios/UndefinedInstructionScenario.m +++ b/features/fixtures/shared/scenarios/UndefinedInstructionScenario.m @@ -25,6 +25,7 @@ */ #import "Scenario.h" +#import "Logging.h" #import "spin_malloc.h" diff --git a/features/fixtures/shared/scenarios/UnhandledErrorThreadSendAlwaysScenario.m b/features/fixtures/shared/scenarios/UnhandledErrorThreadSendAlwaysScenario.m index 3f8840ab0..b23f297bf 100644 --- a/features/fixtures/shared/scenarios/UnhandledErrorThreadSendAlwaysScenario.m +++ b/features/fixtures/shared/scenarios/UnhandledErrorThreadSendAlwaysScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface UnhandledErrorThreadSendAlwaysScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/UnhandledErrorThreadSendNeverScenario.m b/features/fixtures/shared/scenarios/UnhandledErrorThreadSendNeverScenario.m index 64d06dc81..36df09b01 100644 --- a/features/fixtures/shared/scenarios/UnhandledErrorThreadSendNeverScenario.m +++ b/features/fixtures/shared/scenarios/UnhandledErrorThreadSendNeverScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface UnhandledErrorThreadSendNeverScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/UnhandledMachExceptionOverrideScenario.m b/features/fixtures/shared/scenarios/UnhandledMachExceptionOverrideScenario.m index 4131adc1d..ac5feb761 100644 --- a/features/fixtures/shared/scenarios/UnhandledMachExceptionOverrideScenario.m +++ b/features/fixtures/shared/scenarios/UnhandledMachExceptionOverrideScenario.m @@ -7,6 +7,7 @@ // #import "MarkUnhandledHandledScenario.h" +#import "Logging.h" @interface UnhandledMachExceptionOverrideScenario : MarkUnhandledHandledScenario @end diff --git a/features/fixtures/shared/scenarios/UnhandledMachExceptionScenario.m b/features/fixtures/shared/scenarios/UnhandledMachExceptionScenario.m index b2d958886..b41682e0c 100644 --- a/features/fixtures/shared/scenarios/UnhandledMachExceptionScenario.m +++ b/features/fixtures/shared/scenarios/UnhandledMachExceptionScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" @interface UnhandledMachExceptionScenario : Scenario @end diff --git a/features/fixtures/shared/scenarios/UserPersistenceDontPersistUserScenario.m b/features/fixtures/shared/scenarios/UserPersistenceDontPersistUserScenario.m index 3cdf7b98c..82b4c0305 100644 --- a/features/fixtures/shared/scenarios/UserPersistenceDontPersistUserScenario.m +++ b/features/fixtures/shared/scenarios/UserPersistenceDontPersistUserScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Set a user but don't persist it diff --git a/features/fixtures/shared/scenarios/UserPersistenceNoUserScenario.m b/features/fixtures/shared/scenarios/UserPersistenceNoUserScenario.m index e352c13ba..7affb9ab6 100644 --- a/features/fixtures/shared/scenarios/UserPersistenceNoUserScenario.m +++ b/features/fixtures/shared/scenarios/UserPersistenceNoUserScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Don't set a user, don't change persistence (defaults to True). diff --git a/features/fixtures/shared/scenarios/UserPersistencePersistUserClientScenario.m b/features/fixtures/shared/scenarios/UserPersistencePersistUserClientScenario.m index bf4ceb2e1..b36aa7fda 100644 --- a/features/fixtures/shared/scenarios/UserPersistencePersistUserClientScenario.m +++ b/features/fixtures/shared/scenarios/UserPersistencePersistUserClientScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Set a user on the client and persist it diff --git a/features/fixtures/shared/scenarios/UserPersistencePersistUserScenario.m b/features/fixtures/shared/scenarios/UserPersistencePersistUserScenario.m index f247cbab8..c793f09b6 100644 --- a/features/fixtures/shared/scenarios/UserPersistencePersistUserScenario.m +++ b/features/fixtures/shared/scenarios/UserPersistencePersistUserScenario.m @@ -7,6 +7,7 @@ // #import "Scenario.h" +#import "Logging.h" /** * Set a user on the config and persist it diff --git a/features/fixtures/shared/utils/BugsnagWrapper.swift b/features/fixtures/shared/utils/BugsnagWrapper.swift index cd51e3d49..79d0d50ba 100644 --- a/features/fixtures/shared/utils/BugsnagWrapper.swift +++ b/features/fixtures/shared/utils/BugsnagWrapper.swift @@ -19,8 +19,8 @@ class BugsnagWrapper : Bugsnag { plistNotifyEndpoint = configuration.endpoints.notify; plistSessionsEndpoint = configuration.endpoints.sessions; - NSLog("Plist notify endpoint: %@", plistNotifyEndpoint); - NSLog("Plist sessions endpoint: %@", plistSessionsEndpoint); + logInfo("Plist notify endpoint: %@", plistNotifyEndpoint); + logInfo("Plist sessions endpoint: %@", plistSessionsEndpoint); if (plistNotifyEndpoint != "http://example.com/notify" || plistSessionsEndpoint != "http://example.com/sessions") { diff --git a/features/fixtures/shared/utils/Logging.swift b/features/fixtures/shared/utils/Logging.swift new file mode 100644 index 000000000..72721666a --- /dev/null +++ b/features/fixtures/shared/utils/Logging.swift @@ -0,0 +1,45 @@ +// +// logging.swift +// iOSTestApp +// +// Created by Karl Stenerud on 02.11.23. +// Copyright © 2023 Bugsnag. All rights reserved. +// + +import Foundation + +//public func logDebug(_ format: String) { +// logDebug(format: format, args: 0 as Int) +//} +public func logDebug(_ format: String, _ args: CVarArg...) { + withVaList(args) { + logInternal("debug", format, $0) + } +} + +//public func logInfo(_ format: String) { +// logInfo(format: format, args: 0 as Int) +//} +public func logInfo(_ format: String, _ args: CVarArg...) { + withVaList(args) { + logInternal("info", format, $0) + } +} + +//public func logWarn(_ format: String) { +// logWarn(format: format, args: 0 as Int) +//} +public func logWarn(_ format: String, _ args: CVarArg...) { + withVaList(args) { + logInternal("warn", format, $0) + } +} + +//public func logError(_ format: String) { +// logError(format: format, args: 0 as Int) +//} +public func logError(_ format: String, _ args: CVarArg...) { + withVaList(args) { + logInternal("error", format, $0) + } +} diff --git a/features/steps/app_steps.rb b/features/steps/app_steps.rb index 54afd4fa6..d0d579c37 100644 --- a/features/steps/app_steps.rb +++ b/features/steps/app_steps.rb @@ -66,7 +66,7 @@ # 4: The application is running in the foreground Then('the app is not running') do - wait_for_true do + wait_for_true('the app is not running') do case Maze::Helper.get_current_platform when 'ios' Maze.driver.app_state('com.bugsnag.fixtures.iOSTestApp') == :not_running @@ -112,7 +112,7 @@ def trigger_app_command end end -def wait_for_true +def wait_for_true(description) max_attempts = 300 attempts = 0 assertion_passed = false @@ -121,7 +121,7 @@ def wait_for_true assertion_passed = yield sleep 0.1 end - raise 'Assertion not passed in 30s' unless assertion_passed + $logger.warn "Assertion not passed in 30s: #{description}" unless assertion_passed end def run_macos_app diff --git a/features/support/env.rb b/features/support/env.rb index e4e4bd9d5..72b2c6012 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -77,6 +77,10 @@ def skip_between(os, version_lo, version_hi) skip_between('ios', 16, 16.99) end +Before('@skip_ios_17') do |_scenario| + skip_between('ios', 17, 17.99) +end + Before('@skip_below_ios_11') do |_scenario| skip_below('ios', 11) end @@ -85,6 +89,10 @@ def skip_between(os, version_lo, version_hi) skip_below('ios', 13) end +Before('@skip_below_ios_13') do |_scenario| + skip_below('ios', 17) +end + Before('@skip_below_macos_10_15') do |_scenario| skip_below('macos', 10.15) end