diff --git a/CHANGELOG.md b/CHANGELOG.md index 11707b1d57..73846c6010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixes + +- Unsupported types with Expando ([#1690](https://github.com/getsentry/sentry-dart/pull/1690)) + ### Features - Breadcrumbs for file I/O operations ([#1649](https://github.com/getsentry/sentry-dart/pull/1649)) diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 2693996d2a..8beacb7096 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -589,6 +589,8 @@ class _WeakMap { final SentryOptions _options; + final throwableHandler = UnsupportedThrowablesHandler(); + _WeakMap(this._options); void add( @@ -599,6 +601,7 @@ class _WeakMap { if (throwable == null) { return; } + throwable = throwableHandler.wrapIfUnsupportedType(throwable); try { if (_expando[throwable] == null) { _expando[throwable] = MapEntry(span, transaction); @@ -617,6 +620,7 @@ class _WeakMap { if (throwable == null) { return null; } + throwable = throwableHandler.wrapIfUnsupportedType(throwable); try { return _expando[throwable] as MapEntry?; } catch (exception, stackTrace) { @@ -630,3 +634,35 @@ class _WeakMap { return null; } } + +/// A handler for unsupported throwables used for Expando. +@visibleForTesting +class UnsupportedThrowablesHandler { + final _unsupportedTypes = {String, int, double, bool}; + final _unsupportedThrowables = {}; + + dynamic wrapIfUnsupportedType(dynamic throwable) { + if (_unsupportedTypes.contains(throwable.runtimeType)) { + throwable = _UnsupportedExceptionWrapper(Exception(throwable)); + _unsupportedThrowables.add(throwable); + } + return _unsupportedThrowables.lookup(throwable) ?? throwable; + } +} + +class _UnsupportedExceptionWrapper { + _UnsupportedExceptionWrapper(this.exception); + + final Exception exception; + + @override + bool operator ==(Object other) { + if (other is _UnsupportedExceptionWrapper) { + return other.exception.toString() == exception.toString(); + } + return false; + } + + @override + int get hashCode => exception.toString().hashCode; +} diff --git a/dart/test/hub_test.dart b/dart/test/hub_test.dart index 8cc4e99502..c14239e474 100644 --- a/dart/test/hub_test.dart +++ b/dart/test/hub_test.dart @@ -148,8 +148,8 @@ void main() { final capturedEvent = fixture.client.captureEventCalls.first; - expect(capturedEvent.event.transaction, isNull); - expect(capturedEvent.event.contexts.trace, isNull); + expect(capturedEvent.event.transaction, 'test'); + expect(capturedEvent.event.contexts.trace, isNotNull); }); }); diff --git a/dart/test/unsupported_throwables_test.dart b/dart/test/unsupported_throwables_test.dart new file mode 100644 index 0000000000..9cac063a34 --- /dev/null +++ b/dart/test/unsupported_throwables_test.dart @@ -0,0 +1,92 @@ +import 'package:sentry/src/hub.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +void main() { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + group('unsupported throwable types', () { + test('wrapped string throwable does not throw when expanding', () async { + final throwableHandler = fixture.sut; + final unsupportedThrowable = 'test throwable'; + final wrappedThrowable = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + + expect(() { + fixture.expando[wrappedThrowable]; + }, returnsNormally); + }); + + test('wrapped int throwable does not throw when expanding', () async { + final throwableHandler = fixture.sut; + final unsupportedThrowable = 1; + final wrappedThrowable = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + + expect(() { + fixture.expando[wrappedThrowable]; + }, returnsNormally); + }); + + test('wrapped double throwable does not throw when expanding', () async { + final throwableHandler = fixture.sut; + final unsupportedThrowable = 1.0; + final wrappedThrowable = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + + expect(() { + fixture.expando[wrappedThrowable]; + }, returnsNormally); + }); + + test('wrapped bool throwable does not throw when expanding', () async { + final throwableHandler = fixture.sut; + final unsupportedThrowable = true; + final wrappedThrowable = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + + expect(() { + fixture.expando[wrappedThrowable]; + }, returnsNormally); + }); + + test( + 'creating multiple instances of string wrapped exceptions accesses the same expando value', + () async { + final unsupportedThrowable = 'test throwable'; + final throwableHandler = fixture.sut; + + final first = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + fixture.expando[first] = 1; + + final second = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + expect(fixture.expando[second], 1); + fixture.expando[second] = 2.0; + + final third = + throwableHandler.wrapIfUnsupportedType(unsupportedThrowable); + expect(fixture.expando[third], 2.0); + }); + }); + + group('supported throwable type', () { + test('does not wrap exception if it is a supported type', () async { + final supportedThrowable = Exception('test throwable'); + final result = fixture.sut.wrapIfUnsupportedType(supportedThrowable); + + expect(result, supportedThrowable); + }); + }); +} + +class Fixture { + final expando = Expando(); + + UnsupportedThrowablesHandler get sut => UnsupportedThrowablesHandler(); +} diff --git a/dio/pubspec.yaml b/dio/pubspec.yaml index 56e5102e60..ce7a826218 100644 --- a/dio/pubspec.yaml +++ b/dio/pubspec.yaml @@ -4,7 +4,7 @@ version: 7.10.1 homepage: https://docs.sentry.io/platforms/dart/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues -documentation: https://docs.sentry.io/platforms/dart/configuration/integrations/dio/ +documentation: https://docs.sentry.io/platforms/dart/integrations/dio/ environment: sdk: '>=2.17.0 <4.0.0' diff --git a/logging/pubspec.yaml b/logging/pubspec.yaml index a9394bc92c..5deb649563 100644 --- a/logging/pubspec.yaml +++ b/logging/pubspec.yaml @@ -4,7 +4,7 @@ version: 7.10.1 homepage: https://docs.sentry.io/platforms/dart/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues -documentation: https://docs.sentry.io/platforms/dart/configuration/integrations/logging/ +documentation: https://docs.sentry.io/platforms/dart/integrations/logging/ environment: sdk: '>=2.17.0 <4.0.0'