diff --git a/CHANGELOG.md b/CHANGELOG.md index 961dbbef..d90ed0e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## TBD + +- Fixed: Navigator.pushAndRemoveUntil throws exception [#242](https://github.com/bugsnag/bugsnag-flutter/pull/242) ## 3.1.0 (2024-04-09) diff --git a/features/fixtures/app/lib/scenarios/null_context_scenario.dart b/features/fixtures/app/lib/scenarios/null_context_scenario.dart new file mode 100644 index 00000000..24b80750 --- /dev/null +++ b/features/fixtures/app/lib/scenarios/null_context_scenario.dart @@ -0,0 +1,11 @@ +import 'package:bugsnag_flutter/bugsnag_flutter.dart'; +import 'scenario.dart'; + +class NullContextScenario extends Scenario { + @override + Future run() async { + await bugsnag.start(endpoints: endpoints); + await bugsnag.setContext(null); + await bugsnag.notify(Exception(), null); + } +} diff --git a/features/fixtures/app/lib/scenarios/null_user_scenario.dart b/features/fixtures/app/lib/scenarios/null_user_scenario.dart new file mode 100644 index 00000000..07a11410 --- /dev/null +++ b/features/fixtures/app/lib/scenarios/null_user_scenario.dart @@ -0,0 +1,11 @@ +import 'package:bugsnag_flutter/bugsnag_flutter.dart'; +import 'scenario.dart'; + +class NullUserScenario extends Scenario { + @override + Future run() async { + await bugsnag.start(endpoints: endpoints); + await bugsnag.setUser(id: null, email: null, name: null); + await bugsnag.notify(Exception(), null); + } +} diff --git a/features/fixtures/app/lib/scenarios/scenarios.dart b/features/fixtures/app/lib/scenarios/scenarios.dart index 664676c5..dbbaacca 100644 --- a/features/fixtures/app/lib/scenarios/scenarios.dart +++ b/features/fixtures/app/lib/scenarios/scenarios.dart @@ -1,3 +1,6 @@ +import 'package:MazeRunner/scenarios/null_context_scenario.dart'; +import 'package:MazeRunner/scenarios/null_user_scenario.dart'; + import 'app_hang_scenario.dart'; import 'attach_bugsnag_scenario.dart'; import 'breadcrumbs_scenario.dart'; @@ -58,5 +61,8 @@ final List> scenarios = [ ScenarioInfo( 'UnhandledExceptionScenario', () => UnhandledExceptionScenario()), ScenarioInfo("HttpBreadcrumbScenario", () => HttpBreadcrumbScenario()), - ScenarioInfo("DartIoHttpBreadcrumbScenario", () => DartIoHttpBreadcrumbScenario()), + ScenarioInfo( + "DartIoHttpBreadcrumbScenario", () => DartIoHttpBreadcrumbScenario()), + ScenarioInfo("NullContextScenario", () => NullContextScenario()), + ScenarioInfo("NullUserScenario", () => NullUserScenario()), ]; diff --git a/features/null_parameters.feature b/features/null_parameters.feature new file mode 100644 index 00000000..a4364117 --- /dev/null +++ b/features/null_parameters.feature @@ -0,0 +1,15 @@ +Feature: nullParameters + + Scenario: Context is set to null + When I run "NullContextScenario" + Then I wait to receive an error + And the error is valid for the error reporting API version "4.0" for the "Flutter Bugsnag Notifier" notifier + And the exception "errorClass" equals "_Exception" + And the event "severity" equals "warning" + + Scenario: User is set to null + When I run "NullUserScenario" + Then I wait to receive an error + And the error is valid for the error reporting API version "4.0" for the "Flutter Bugsnag Notifier" notifier + And the exception "errorClass" equals "_Exception" + And the event "severity" equals "warning" \ No newline at end of file diff --git a/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java b/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java index 4b9242f3..447cde66 100644 --- a/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java +++ b/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java @@ -104,18 +104,18 @@ Void start(@Nullable JSONObject args) throws Exception { ? new Configuration(arguments.getString("apiKey")) : Configuration.load(context); - configuration.setAppType(arguments.optString("appType", configuration.getAppType())); - configuration.setAppVersion(arguments.optString("appVersion", configuration.getAppVersion())); + configuration.setAppType(getString(arguments, "appType", configuration.getAppType())); + configuration.setAppVersion(getString(arguments, "appVersion", configuration.getAppVersion())); configuration.setAutoTrackSessions(arguments.optBoolean("autoTrackSessions", configuration.getAutoTrackSessions())); configuration.setAutoDetectErrors(arguments.optBoolean("autoDetectErrors", configuration.getAutoDetectErrors())); - configuration.setContext(arguments.optString("context", configuration.getContext())); + configuration.setContext(getString(arguments, "context", configuration.getContext())); configuration.setLaunchDurationMillis(arguments.optLong("launchDurationMillis", configuration.getLaunchDurationMillis())); configuration.setSendLaunchCrashesSynchronously(arguments.optBoolean("sendLaunchCrashesSynchronously", configuration.getSendLaunchCrashesSynchronously())); configuration.setMaxBreadcrumbs(arguments.optInt("maxBreadcrumbs", configuration.getMaxBreadcrumbs())); configuration.setMaxPersistedEvents(arguments.optInt("maxPersistedEvents", configuration.getMaxPersistedEvents())); configuration.setMaxPersistedSessions(arguments.optInt("maxPersistedSessions", configuration.getMaxPersistedSessions())); configuration.setMaxStringValueLength(arguments.optInt("maxStringValueLength", configuration.getMaxStringValueLength())); - configuration.setReleaseStage(arguments.optString("releaseStage", configuration.getReleaseStage())); + configuration.setReleaseStage(getString(arguments, "releaseStage", configuration.getReleaseStage())); configuration.setPersistUser(arguments.optBoolean("persistUser", configuration.getPersistUser())); if (arguments.has("redactedKeys")) { @@ -133,9 +133,9 @@ Void start(@Nullable JSONObject args) throws Exception { JSONObject user = arguments.optJSONObject("user"); if (user != null) { configuration.setUser( - user.optString("id", null), - user.optString("email", null), - user.optString("name", null) + getString(user, "id"), + getString(user, "email"), + getString(user, "name") ); } @@ -228,9 +228,9 @@ JSONObject getUser(@Nullable JSONObject args) { Void setUser(@Nullable JSONObject user) { if (user != null) { Bugsnag.setUser( - (String) user.opt("id"), - (String) user.opt("email"), - (String) user.opt("name") + getString(user, "id"), + getString(user, "email"), + getString(user, "name") ); } else { Bugsnag.setUser(null, null, null); @@ -241,7 +241,7 @@ Void setUser(@Nullable JSONObject user) { Void setContext(@Nullable JSONObject args) { if (args != null) { - Bugsnag.setContext((String) args.opt("context")); + Bugsnag.setContext(getString(args, "context")); } return null; @@ -253,9 +253,9 @@ String getContext(@Nullable JSONObject args) { Void leaveBreadcrumb(@Nullable JSONObject args) throws Exception { if (args != null && - args.has("name") && + hasString(args, "name") && args.has("metaData") && - args.has("type")) { + hasString(args, "type")) { Bugsnag.leaveBreadcrumb(args.getString("name"), JsonHelper.unwrap(args.getJSONObject("metaData")), JsonHelper.unpackBreadcrumbType(args.getString("type"))); @@ -279,7 +279,7 @@ Void addFeatureFlags(@Nullable JSONArray args) { } Void clearFeatureFlag(@Nullable JSONObject args) throws JSONException { - if (args != null && args.has("name")) { + if (args != null && hasString(args, "name")) { Bugsnag.clearFeatureFlag(args.getString("name")); } return null; @@ -291,7 +291,7 @@ Void clearFeatureFlags(@Nullable JSONObject args) { } Void addMetadata(@Nullable JSONObject args) throws JSONException { - if (args == null || !args.has("section") || !args.has("metadata")) { + if (args == null || !hasString(args,"section") || !args.has("metadata")) { return null; } @@ -303,11 +303,11 @@ Void addMetadata(@Nullable JSONObject args) throws JSONException { } Void clearMetadata(@Nullable JSONObject args) throws JSONException { - if (args == null || !args.has("section")) { + if (args == null || !hasString(args, "section")) { return null; } - if (args.has("key")) { + if (hasString(args, "key")) { Bugsnag.clearMetadata(args.getString("section"), args.getString("key")); } else { Bugsnag.clearMetadata(args.getString("section")); @@ -317,7 +317,7 @@ Void clearMetadata(@Nullable JSONObject args) throws JSONException { } JSONObject getMetadata(@Nullable JSONObject args) throws JSONException { - if (args == null || !args.has("section")) { + if (args == null || !hasString(args, "section")) { return null; } @@ -403,4 +403,18 @@ JSONObject deliverEvent(@Nullable JSONObject eventJson) { client.deliverEvent(event); return null; } + + @Nullable String getString(JSONObject args, String key) { + Object value = args.opt(key); + return value instanceof String ? (String) value : null; + } + + @Nullable String getString(JSONObject args, String key, @Nullable String fallback) { + String value = getString(args, key); + return value != null ? value : fallback; + } + + boolean hasString(JSONObject args, String key) { + return getString(args, key) != null; + } }