Repository: cfug/dio

Issue:
[Proposal] Improve toString() of InterceptorState
### Request Statement

When Firebase Crashlytics gets an error report from code within a request interceptor,
the information from the log is very limited.

For example:

```
// Crashlytics report header
DioMixin.request
io.flutter.plugins.firebase.crashlytics.FlutterError - Instance of 'InterceptorState<DioException>'

// Raw stacktrace
      Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Instance of 'InterceptorState<DioException>'
       at DioMixin.request(dio_mixin.dart:350)
       at DioMixin.get(dio_mixin.dart:64)
       at HttpChatRepository.getChatMessages(http_chat_repository.dart:12)
       at ChatNotifier.fetchMessages(chat_notifier.dart:38)
       at PollingManager._queue(polling_manager.dart:19)
       at PollingManager.startPolling.<fn>(polling_manager.dart:32)
```

### Solution Brainstorm

Instead of having `InterceptorState<T>` use the default toString() implementation,
which is `Instance of 'InterceptorState<DioException>'`,
provide the error details of the underlying DioException in the toString() implementation,
by implementing `toString()` in https://github.com/cfug/dio/blob/f87a09566c076936be236e3313f8843d6d60564c/dio/lib/src/interceptor.dart#L14
and providing the details of the DioException in the toString() implementation.



Fix patch:
diff --git a/dio/CHANGELOG.md b/dio/CHANGELOG.md
index 310727a0a..abeaeb470 100644
--- a/dio/CHANGELOG.md
+++ b/dio/CHANGELOG.md
@@ -9,6 +9,7 @@ See the [Migration Guide][] for the complete breaking changes list.**
 - Add constructor for `DioExceptionType.badCertificate`.
 - Create type alias `DioMediaType` for `http_parser`'s `MediaType`.
 - Fix the type conversion regression when using `MultipartFile.fromBytes`.
+- Improves `InterceptorState.toString()`.
 
 ## 5.4.3+1
 
diff --git a/dio/lib/src/interceptor.dart b/dio/lib/src/interceptor.dart
index a062ebb28..b4e1a8321 100644
--- a/dio/lib/src/interceptor.dart
+++ b/dio/lib/src/interceptor.dart
@@ -1,6 +1,6 @@
 part of 'dio_mixin.dart';
 
-/// @nodoc
+/// The result type after handled by the interceptor.
 enum InterceptorResultType {
   next,
   resolve,
@@ -10,12 +10,14 @@ enum InterceptorResultType {
 }
 
 /// Used to pass state between interceptors.
-/// @nodoc
 class InterceptorState<T> {
   const InterceptorState(this.data, [this.type = InterceptorResultType.next]);
 
   final T data;
   final InterceptorResultType type;
+
+  @override
+  String toString() => 'InterceptorState<$T>(type: $type, data: $data)';
 }
 
 abstract class _BaseHandler {


Test patch:
diff --git a/dio/test/interceptor_test.dart b/dio/test/interceptor_test.dart
index 142e063ef..531387a93 100644
--- a/dio/test/interceptor_test.dart
+++ b/dio/test/interceptor_test.dart
@@ -1,6 +1,7 @@
 import 'dart:async';
 
 import 'package:dio/dio.dart';
+import 'package:dio/src/dio_mixin.dart';
 import 'package:dio/src/interceptors/imply_content_type.dart';
 import 'package:test/test.dart';
 
@@ -85,6 +86,20 @@ void main() {
     );
   });
 
+  group('InterceptorState', () {
+    test('toString()', () {
+      final data = DioException(requestOptions: RequestOptions());
+      final state = InterceptorState<DioException>(data);
+      expect(
+        state.toString(),
+        'InterceptorState<DioException>('
+        'type: InterceptorResultType.next, '
+        'data: DioException [unknown]: null'
+        ')',
+      );
+    });
+  });
+
   group('Request Interceptor', () {
     test('interceptor chain', () async {
       final dio = Dio();