[in_app_purchase] Add toString() to IAPError (#4162)

This adds toString() to the IAPError class. This is so it is easier to see what is causing IAPError's in error logs.
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_platform_interface/CHANGELOG.md
index ec619d2..cd4b86d 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.2.0
+
+* Added `toString()` to `IAPError`
+
 ## 1.1.0
 
 * Added `currencySymbol` in ProductDetails.
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/errors.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/errors.dart
index 7b788aa..8e10997 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/errors.dart
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/errors.dart
@@ -2,4 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+export 'in_app_purchase_error.dart';
 export 'in_app_purchase_exception.dart';
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/in_app_purchase_error.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/in_app_purchase_error.dart
similarity index 88%
rename from packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/in_app_purchase_error.dart
rename to packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/in_app_purchase_error.dart
index f305f57..166646d 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/in_app_purchase_error.dart
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/errors/in_app_purchase_error.dart
@@ -28,4 +28,9 @@
 
   /// Error details, possibly null.
   final dynamic details;
+
+  @override
+  String toString() {
+    return 'IAPError(code: $code, source: $source, message: $message, details: $details)';
+  }
 }
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart
index 11b244a..3a9d7c3 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'in_app_purchase_error.dart';
+import '../errors/in_app_purchase_error.dart';
 import 'product_details.dart';
 
 /// The response returned by [InAppPurchasePlatform.queryProductDetails].
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/purchase_details.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/purchase_details.dart
index 08d0efe..8c98beb 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/purchase_details.dart
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/purchase_details.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'in_app_purchase_error.dart';
+import '../errors/in_app_purchase_error.dart';
 import 'purchase_status.dart';
 import 'purchase_verification_data.dart';
 
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/types.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/types.dart
index 33d183c..7cb6664 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/types.dart
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/types.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export 'in_app_purchase_error.dart';
 export 'product_details.dart';
 export 'product_details_response.dart';
 export 'purchase_details.dart';
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_platform_interface/pubspec.yaml
index d15e5f4..64574e0 100644
--- a/packages/in_app_purchase/in_app_purchase_platform_interface/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/pubspec.yaml
@@ -4,7 +4,7 @@
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.1.0
+version: 1.2.0
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/src/errors/in_app_purchase_error_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/src/errors/in_app_purchase_error_test.dart
new file mode 100644
index 0000000..ed63f49
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/src/errors/in_app_purchase_error_test.dart
@@ -0,0 +1,29 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:in_app_purchase_platform_interface/src/errors/in_app_purchase_error.dart';
+
+void main() {
+  test('toString: Should return a description of the error', () {
+    final IAPError exceptionNoDetails = IAPError(
+      code: 'error_code',
+      message: 'dummy_message',
+      source: 'dummy_source',
+    );
+
+    expect(exceptionNoDetails.toString(),
+        'IAPError(code: error_code, source: dummy_source, message: dummy_message, details: null)');
+
+    final IAPError exceptionWithDetails = IAPError(
+      code: 'error_code',
+      message: 'dummy_message',
+      source: 'dummy_source',
+      details: 'dummy_details',
+    );
+
+    expect(exceptionWithDetails.toString(),
+        'IAPError(code: error_code, source: dummy_source, message: dummy_message, details: dummy_details)');
+  });
+}